From 26d66923767581d63fdfc303525cddebf9125bde Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 7 Aug 2010 14:15:21 +0000 Subject: [PATCH] 2010-08-07 Tatsuhiro Tsujikawa 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 --- ChangeLog | 55 +++++++- src/BtSetup.cc | 37 ++++-- src/DHTAutoSaveCommand.cc | 10 +- src/DHTAutoSaveCommand.h | 5 +- src/DHTConnectionImpl.cc | 24 ++-- src/DHTConnectionImpl.h | 21 ++-- src/DHTEntryPointNameResolveCommand.cc | 7 +- src/DHTFindNodeReplyMessage.cc | 24 ++-- src/DHTFindNodeReplyMessage.h | 7 +- src/DHTGetPeersMessage.cc | 17 +-- src/DHTGetPeersReplyMessage.cc | 46 ++++--- src/DHTGetPeersReplyMessage.h | 7 +- src/DHTMessageFactory.h | 6 - src/DHTMessageFactoryImpl.cc | 125 ++++++++---------- src/DHTMessageFactoryImpl.h | 27 ++-- src/DHTMessageTracker.cc | 27 ++-- src/DHTRegistry.cc | 31 +++-- src/DHTRegistry.h | 40 ++++++ src/DHTRoutingTableDeserializer.cc | 40 +++--- src/DHTRoutingTableDeserializer.h | 4 +- src/DHTRoutingTableSerializer.cc | 26 ++-- src/DHTRoutingTableSerializer.h | 4 +- src/DHTSetup.cc | 89 ++++++++----- src/DHTSetup.h | 7 +- src/FtpConnection.cc | 2 +- src/LpdMessageReceiver.cc | 2 +- src/OptionHandlerFactory.cc | 48 +++++++ src/OptionHandlerImpl.h | 15 +-- src/PeerInteractionCommand.cc | 51 ++++++-- src/RequestGroup.cc | 48 +++++-- src/SocketCore.cc | 40 +++--- src/SocketCore.h | 5 +- src/bittorrent_helper.cc | 11 ++ src/bittorrent_helper.h | 5 + src/prefs.cc | 14 +++ src/prefs.h | 14 +++ src/usage_text.h | 28 +++-- test/DHTConnectionImplTest.cc | 15 ++- test/DHTFindNodeReplyMessageTest.cc | 51 +++++++- test/DHTGetPeersMessageTest.cc | 28 ++--- test/DHTGetPeersReplyMessageTest.cc | 91 +++++++++++--- test/DHTMessageFactoryImplTest.cc | 134 +++++++++++++++++--- test/DHTRoutingTableDeserializerTest.cc | 47 ++++++- test/DHTRoutingTableSerializerTest.cc | 161 ++++++++++++++++++++---- test/LpdMessageDispatcherTest.cc | 2 +- test/MockDHTMessageFactory.h | 15 +-- 46 files changed, 1098 insertions(+), 415 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f8943a9..b2ea2662 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,57 @@ -2010-08-05 Tatsuhiro Tsujikawa +2010-08-07 Tatsuhiro Tsujikawa + + 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 Removed AI_V4MAPPED from DEFAULT_AI_FLAGS * src/a2netcompat.h diff --git a/src/BtSetup.cc b/src/BtSetup.cc index f17757e5..fdd467fa 100644 --- a/src/BtSetup.cc +++ b/src/BtSetup.cc @@ -58,6 +58,15 @@ #include "DHTPeerAnnounceStorage.h" #include "DHTSetup.h" #include "DHTRegistry.h" +#include "DHTNode.h" +#include "DHTRoutingTable.h" +#include "DHTTaskQueue.h" +#include "DHTTaskFactory.h" +#include "DHTTokenTracker.h" +#include "DHTMessageDispatcher.h" +#include "DHTMessageReceiver.h" +#include "DHTMessageFactory.h" +#include "DHTMessageCallback.h" #include "BtProgressInfoFile.h" #include "BtAnnounce.h" #include "BtRuntime.h" @@ -126,15 +135,25 @@ void BtSetup::setup(std::vector& commands, commands.push_back(c); } - if((metadataGetMode || !torrentAttrs->privateTorrent) && - DHTSetup::initialized()) { - DHTGetPeersCommand* command = - new DHTGetPeersCommand(e->newCUID(), requestGroup, e); - command->setTaskQueue(DHTRegistry::getData().taskQueue); - command->setTaskFactory(DHTRegistry::getData().taskFactory); - command->setBtRuntime(btRuntime); - command->setPeerStorage(peerStorage); - commands.push_back(command); + if(metadataGetMode || !torrentAttrs->privateTorrent) { + if(DHTRegistry::isInitialized()) { + DHTGetPeersCommand* command = + new DHTGetPeersCommand(e->newCUID(), requestGroup, e); + command->setTaskQueue(DHTRegistry::getData().taskQueue); + command->setTaskFactory(DHTRegistry::getData().taskFactory); + command->setBtRuntime(btRuntime); + command->setPeerStorage(peerStorage); + commands.push_back(command); + } + if(DHTRegistry::isInitialized6()) { + DHTGetPeersCommand* command = + new DHTGetPeersCommand(e->newCUID(), requestGroup, e); + command->setTaskQueue(DHTRegistry::getData6().taskQueue); + command->setTaskFactory(DHTRegistry::getData6().taskFactory); + command->setBtRuntime(btRuntime); + command->setPeerStorage(peerStorage); + commands.push_back(command); + } } if(!metadataGetMode) { SharedHandle unionCri(new UnionSeedCriteria()); diff --git a/src/DHTAutoSaveCommand.cc b/src/DHTAutoSaveCommand.cc index f5ae60ec..63f8b2c6 100644 --- a/src/DHTAutoSaveCommand.cc +++ b/src/DHTAutoSaveCommand.cc @@ -62,8 +62,9 @@ namespace aria2 { DHTAutoSaveCommand::DHTAutoSaveCommand -(cuid_t cuid, DownloadEngine* e, time_t interval): - TimeBasedCommand(cuid, e, interval) {} +(cuid_t cuid, DownloadEngine* e, int family, time_t interval): + TimeBasedCommand(cuid, e, interval), + family_(family) {} DHTAutoSaveCommand::~DHTAutoSaveCommand() {} @@ -84,7 +85,8 @@ void DHTAutoSaveCommand::process() void DHTAutoSaveCommand::save() { std::string dhtFile = - getDownloadEngine()->getOption()->get(PREF_DHT_FILE_PATH); + getDownloadEngine()->getOption()-> + get(family_ == AF_INET? PREF_DHT_FILE_PATH : PREF_DHT_FILE_PATH6); getLogger()->info("Saving DHT routing table to %s.", dhtFile.c_str()); std::string tempFile = dhtFile; @@ -116,7 +118,7 @@ void DHTAutoSaveCommand::save() nodes.insert(nodes.end(), goodNodes.begin(), goodNodes.end()); } - DHTRoutingTableSerializer serializer; + DHTRoutingTableSerializer serializer(family_); serializer.setLocalNode(localNode_); serializer.setNodes(nodes); diff --git a/src/DHTAutoSaveCommand.h b/src/DHTAutoSaveCommand.h index f7a0ad5a..1a14e90e 100644 --- a/src/DHTAutoSaveCommand.h +++ b/src/DHTAutoSaveCommand.h @@ -46,13 +46,16 @@ class DHTNode; class DHTAutoSaveCommand : public TimeBasedCommand { private: + int family_; + SharedHandle localNode_; SharedHandle routingTable_; void save(); public: - DHTAutoSaveCommand(cuid_t cuid, DownloadEngine* e, time_t interval); + DHTAutoSaveCommand + (cuid_t cuid, DownloadEngine* e, int family, time_t interval); virtual ~DHTAutoSaveCommand(); diff --git a/src/DHTConnectionImpl.cc b/src/DHTConnectionImpl.cc index 26bd31ce..9a2e44f6 100644 --- a/src/DHTConnectionImpl.cc +++ b/src/DHTConnectionImpl.cc @@ -46,12 +46,15 @@ namespace aria2 { -DHTConnectionImpl::DHTConnectionImpl():socket_(new SocketCore(SOCK_DGRAM)), - logger_(LogFactory::getInstance()) {} +DHTConnectionImpl::DHTConnectionImpl(int family): + socket_(new SocketCore(SOCK_DGRAM)), + family_(family), + logger_(LogFactory::getInstance()) {} DHTConnectionImpl::~DHTConnectionImpl() {} -bool DHTConnectionImpl::bind(uint16_t& port, IntSequence& ports) +bool DHTConnectionImpl::bind +(uint16_t& port, const std::string& addr, IntSequence& ports) { std::vector randPorts = ports.flush(); std::random_shuffle(randPorts.begin(), randPorts.end(), @@ -63,25 +66,30 @@ bool DHTConnectionImpl::bind(uint16_t& port, IntSequence& ports) continue; } port = (*portItr); - if(bind(port)) { + if(bind(port, addr)) { return true; } } return false; } -bool DHTConnectionImpl::bind(uint16_t& port) +bool DHTConnectionImpl::bind(uint16_t& port, const std::string& addr) { + int ipv = family_ == AF_INET?4:6; try { - socket_->bind(port); + if(addr.empty()) { + socket_->bind(A2STR::NIL, port, family_); + } else { + socket_->bind(addr, port, family_); + } socket_->setNonBlockingMode(); std::pair svaddr; socket_->getAddrInfo(svaddr); port = svaddr.second; - logger_->notice("DHT: listening to port %d", port); + logger_->notice("IPv%d DHT: listening to port %d", ipv, port); return true; } catch(RecoverableException& e) { - logger_->error("Failed to bind for DHT. port=%u", e, port); + logger_->error("Failed to bind for IPv%d DHT. port=%u", e, ipv, port); } return false; } diff --git a/src/DHTConnectionImpl.h b/src/DHTConnectionImpl.h index 24099edd..7f0808fa 100644 --- a/src/DHTConnectionImpl.h +++ b/src/DHTConnectionImpl.h @@ -48,28 +48,33 @@ class DHTConnectionImpl:public DHTConnection { private: SharedHandle socket_; + int family_; + Logger* logger_; public: - DHTConnectionImpl(); + DHTConnectionImpl(int family); virtual ~DHTConnectionImpl(); /** - * Binds port. All number in ports are tried. - * If successful, the binded port is assigned to port and returns true. - * Otherwise return false and port is undefined in this case. + * Binds port. All number in ports are tried. If successful, the + * binded port is assigned to port and returns true. Otherwise + * return false and port is undefined in this case. If non-empty + * string addr is given, the socket is associated to the address. */ - bool bind(uint16_t& port, IntSequence& ports); + bool bind(uint16_t& port, const std::string& addr, IntSequence& ports); /** * Binds port. The port number specified by port is used to bind. - * If successful, the binded port is assigned to port and returns true. - * Otherwise return false and port is undefined in this case. + * If successful, the binded port is assigned to port and returns + * true. Otherwise return false and port is undefined in this case. + * If non-empty string addr is given, the socket is associated to + * the address. * * If you want to bind arbitrary port, give 0 as port and if successful, * the binded port is assigned to port. */ - bool bind(uint16_t& port); + bool bind(uint16_t& port, const std::string& addr); virtual ssize_t receiveMessage(unsigned char* data, size_t len, std::string& host, uint16_t& port); diff --git a/src/DHTEntryPointNameResolveCommand.cc b/src/DHTEntryPointNameResolveCommand.cc index 9db92f60..d59cbdec 100644 --- a/src/DHTEntryPointNameResolveCommand.cc +++ b/src/DHTEntryPointNameResolveCommand.cc @@ -96,7 +96,12 @@ bool DHTEntryPointNameResolveCommand::execute() while(!entryPoints_.empty()) { std::string hostname = entryPoints_.front().first; try { - if(resolveHostname(hostname, resolver_)) { + if(util::isNumericHost(hostname)) { + std::pair p + (hostname, entryPoints_.front().second); + resolvedEntryPoints_.push_back(p); + addPingTask(p); + } else if(resolveHostname(hostname, resolver_)) { hostname = resolver_->getResolvedAddresses().front(); std::pair p(hostname, entryPoints_.front().second); diff --git a/src/DHTFindNodeReplyMessage.cc b/src/DHTFindNodeReplyMessage.cc index 99acbce1..4c255332 100644 --- a/src/DHTFindNodeReplyMessage.cc +++ b/src/DHTFindNodeReplyMessage.cc @@ -51,11 +51,15 @@ const std::string DHTFindNodeReplyMessage::FIND_NODE("find_node"); const std::string DHTFindNodeReplyMessage::NODES("nodes"); +const std::string DHTFindNodeReplyMessage::NODES6("nodes6"); + DHTFindNodeReplyMessage::DHTFindNodeReplyMessage -(const SharedHandle& localNode, +(int family, + const SharedHandle& localNode, const SharedHandle& remoteNode, const std::string& transactionID): - DHTResponseMessage(localNode, remoteNode, transactionID) {} + DHTResponseMessage(localNode, remoteNode, transactionID), + family_(family) {} DHTFindNodeReplyMessage::~DHTFindNodeReplyMessage() {} @@ -73,23 +77,27 @@ SharedHandle DHTFindNodeReplyMessage::getResponse() { SharedHandle aDict = Dict::g(); aDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH)); + unsigned char buffer[DHTBucket::K*38]; + const int clen = bittorrent::getCompactLength(family_); + const int unit = clen+20; + assert(unit <= 38); size_t offset = 0; - unsigned char buffer[DHTBucket::K*26]; - // TODO if closestKNodes_.size() > DHTBucket::K ?? + size_t k = 0; for(std::vector >::const_iterator i = closestKNodes_.begin(), eoi = closestKNodes_.end(); - i != eoi && offset < DHTBucket::K*26; ++i) { + i != eoi && k < DHTBucket::K; ++i) { SharedHandle node = *i; memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH); unsigned char compact[COMPACT_LEN_IPV6]; int compactlen = bittorrent::packcompact (compact, node->getIPAddress(), node->getPort()); - if(compactlen == COMPACT_LEN_IPV4) { + if(compactlen == clen) { memcpy(buffer+20+offset, compact, compactlen); - offset += 26; + offset += unit; + ++k; } } - aDict->put(NODES, String::g(buffer, offset)); + aDict->put(family_ == AF_INET?NODES:NODES6, String::g(buffer, offset)); return aDict; } diff --git a/src/DHTFindNodeReplyMessage.h b/src/DHTFindNodeReplyMessage.h index 9e14bd2c..15f1dd5d 100644 --- a/src/DHTFindNodeReplyMessage.h +++ b/src/DHTFindNodeReplyMessage.h @@ -42,11 +42,14 @@ namespace aria2 { class DHTFindNodeReplyMessage:public DHTResponseMessage { private: + int family_; + std::vector > closestKNodes_; protected: virtual std::string toStringOptional() const; public: - DHTFindNodeReplyMessage(const SharedHandle& localNode, + DHTFindNodeReplyMessage(int family, + const SharedHandle& localNode, const SharedHandle& remoteNode, const std::string& transactionID); @@ -71,6 +74,8 @@ public: static const std::string FIND_NODE; static const std::string NODES; + + static const std::string NODES6; }; } // namespace aria2 diff --git a/src/DHTGetPeersMessage.cc b/src/DHTGetPeersMessage.cc index 9f838a05..2a553792 100644 --- a/src/DHTGetPeersMessage.cc +++ b/src/DHTGetPeersMessage.cc @@ -70,18 +70,11 @@ void DHTGetPeersMessage::doReceivedAction() // Check to see localhost has the contents which has same infohash std::vector > peers; peerAnnounceStorage_->getPeers(peers, infoHash_); - SharedHandle reply; - if(peers.empty()) { - std::vector > nodes; - getRoutingTable()->getClosestKNodes(nodes, infoHash_); - reply = - getMessageFactory()->createGetPeersReplyMessage - (getRemoteNode(), nodes, token, getTransactionID()); - } else { - reply = - getMessageFactory()->createGetPeersReplyMessage - (getRemoteNode(), peers, token, getTransactionID()); - } + std::vector > nodes; + getRoutingTable()->getClosestKNodes(nodes, infoHash_); + SharedHandle reply = + getMessageFactory()->createGetPeersReplyMessage + (getRemoteNode(), nodes, peers, token, getTransactionID()); getMessageDispatcher()->addMessageToQueue(reply); } diff --git a/src/DHTGetPeersReplyMessage.cc b/src/DHTGetPeersReplyMessage.cc index 6a0532c9..76c525c7 100644 --- a/src/DHTGetPeersReplyMessage.cc +++ b/src/DHTGetPeersReplyMessage.cc @@ -57,12 +57,16 @@ const std::string DHTGetPeersReplyMessage::VALUES("values"); const std::string DHTGetPeersReplyMessage::NODES("nodes"); +const std::string DHTGetPeersReplyMessage::NODES6("nodes6"); + DHTGetPeersReplyMessage::DHTGetPeersReplyMessage -(const SharedHandle& localNode, +(int family, + const SharedHandle& localNode, const SharedHandle& remoteNode, const std::string& token, const std::string& transactionID): DHTResponseMessage(localNode, remoteNode, transactionID), + family_(family), token_(token) {} DHTGetPeersReplyMessage::~DHTGetPeersReplyMessage() {} @@ -77,59 +81,69 @@ SharedHandle DHTGetPeersReplyMessage::getResponse() SharedHandle rDict = Dict::g(); rDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH)); rDict->put(TOKEN, token_); - if(values_.empty()) { + // TODO want parameter + if(!closestKNodes_.empty()) { + unsigned char buffer[DHTBucket::K*38]; + const int clen = bittorrent::getCompactLength(family_); + const int unit = clen+20; size_t offset = 0; - unsigned char buffer[DHTBucket::K*26]; + size_t k = 0; for(std::vector >::const_iterator i = closestKNodes_.begin(), eoi = closestKNodes_.end(); - i != eoi && offset < DHTBucket::K*26; ++i) { + i != eoi && k < DHTBucket::K; ++i) { SharedHandle node = *i; memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH); unsigned char compact[COMPACT_LEN_IPV6]; int compactlen = bittorrent::packcompact (compact, node->getIPAddress(), node->getPort()); - if(compactlen == COMPACT_LEN_IPV4) { + if(compactlen == clen) { memcpy(buffer+20+offset, compact, compactlen); - offset += 26; + offset += unit; + ++k; } } - rDict->put(NODES, String::g(buffer, offset)); - } else { + rDict->put(family_ == AF_INET?NODES:NODES6, String::g(buffer, offset)); + } + if(!values_.empty()) { // Limit the size of values list. The maxmum size of UDP datagram // is limited to 65535 bytes. aria2 uses 20bytes token and 2byte // transaction ID. The size of get_peers reply message without - // values list is 87bytes: + // values list and nodes is 87bytes: // // d1:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:token20:aaaaaaaaaaaaaaaaaaaa // 6:valueslee1:t2:bb1:y1:re // + // nodes are 38 bytes per host for IPv6 and the number of hosts is + // K(=8) max. So without values list, we already 87+38*8+4 = 395. + // // Because of Path MTU Discovery, UDP packet size which need not // to be fragmented is much smaller. Since Linux uses Path MTU // Dicoverry by default and returning ICMP message might be // filtered, we should avoid fragmentation. MTU of pppoe is 1492 // max according to RFC2516. We use maximum packet size to be - // 1000. Since it contains 20 bytes IP header and 8 bytes UDP - // header and 87 bytes reply message template described above, We - // can carry (1000-28-87)/8 = 110 peer info. Since DHT spec + // 1024. Since it contains 20 bytes IP header and 8 bytes UDP + // header and 395 bytes reply message template described above, We + // can carry (1024-28-395)/(18+3) = 28 peer info. Since DHT spec // doesn't specify the maximum size of token, reply message - // template may get bigger than 87 bytes. So we use 100 as maximum + // template may get bigger than 395 bytes. So we use 25 as maximum // number of peer info that a message can carry. - static const size_t MAX_VALUES_SIZE = 100; + static const size_t MAX_VALUES_SIZE = 25; SharedHandle valuesList = List::g(); for(std::vector >::const_iterator i = values_.begin(), eoi = values_.end(); i != eoi && valuesList->size() < MAX_VALUES_SIZE; ++i) { const SharedHandle& peer = *i; unsigned char compact[COMPACT_LEN_IPV6]; + const int clen = bittorrent::getCompactLength(family_); int compactlen = bittorrent::packcompact (compact, peer->getIPAddress(), peer->getPort()); - if(compactlen == COMPACT_LEN_IPV4) { + if(compactlen == clen) { valuesList->append(String::g(compact, compactlen)); } } rDict->put(VALUES, valuesList); } - return rDict; + return rDict; } const std::string& DHTGetPeersReplyMessage::getMessageType() const diff --git a/src/DHTGetPeersReplyMessage.h b/src/DHTGetPeersReplyMessage.h index b15a41c4..8494a2d7 100644 --- a/src/DHTGetPeersReplyMessage.h +++ b/src/DHTGetPeersReplyMessage.h @@ -47,6 +47,8 @@ class Peer; class DHTGetPeersReplyMessage:public DHTResponseMessage { private: + int family_; + std::string token_; std::vector > closestKNodes_; @@ -55,7 +57,8 @@ private: protected: virtual std::string toStringOptional() const; public: - DHTGetPeersReplyMessage(const SharedHandle& localNode, + DHTGetPeersReplyMessage(int family, + const SharedHandle& localNode, const SharedHandle& remoteNode, const std::string& token, const std::string& transactionID); @@ -103,6 +106,8 @@ public: static const std::string VALUES; static const std::string NODES; + + static const std::string NODES6; }; } // namespace aria2 diff --git a/src/DHTMessageFactory.h b/src/DHTMessageFactory.h index f0140f12..f363150f 100644 --- a/src/DHTMessageFactory.h +++ b/src/DHTMessageFactory.h @@ -94,12 +94,6 @@ public: createGetPeersReplyMessage (const SharedHandle& remoteNode, const std::vector >& closestKNodes, - const std::string& token, - const std::string& transactionID) = 0; - - virtual SharedHandle - createGetPeersReplyMessage - (const SharedHandle& remoteNode, const std::vector >& peers, const std::string& token, const std::string& transactionID) = 0; diff --git a/src/DHTMessageFactoryImpl.cc b/src/DHTMessageFactoryImpl.cc index 5567711d..9b781115 100644 --- a/src/DHTMessageFactoryImpl.cc +++ b/src/DHTMessageFactoryImpl.cc @@ -64,7 +64,8 @@ namespace aria2 { -DHTMessageFactoryImpl::DHTMessageFactoryImpl(): +DHTMessageFactoryImpl::DHTMessageFactoryImpl(int family): + family_(family), logger_(LogFactory::getInstance()) {} DHTMessageFactoryImpl::~DHTMessageFactoryImpl() {} @@ -261,21 +262,7 @@ DHTMessageFactoryImpl::createResponseMessage } else if(messageType == DHTFindNodeReplyMessage::FIND_NODE) { msg = createFindNodeReplyMessage(remoteNode, dict, transactionID->s()); } else if(messageType == DHTGetPeersReplyMessage::GET_PEERS) { - const List* valuesList = - asList(rDict->get(DHTGetPeersReplyMessage::VALUES)); - if(valuesList) { - msg = createGetPeersReplyMessageWithValues - (remoteNode, dict, transactionID->s()); - } else { - const String* nodes = asString - (rDict->get(DHTGetPeersReplyMessage::NODES)); - if(nodes) { - msg = createGetPeersReplyMessageWithNodes - (remoteNode, dict, transactionID->s()); - } else { - throw DL_ABORT_EX("Malformed DHT message: missing nodes/values"); - } - } + msg = createGetPeersReplyMessage(remoteNode, dict, transactionID->s()); } else if(messageType == DHTAnnouncePeerReplyMessage::ANNOUNCE_PEER) { msg = createAnnouncePeerReplyMessage(remoteNode, transactionID->s()); } else { @@ -349,23 +336,26 @@ DHTMessageFactoryImpl::createFindNodeReplyMessage const std::string& transactionID) { SharedHandle m - (new DHTFindNodeReplyMessage(localNode_, remoteNode, transactionID)); + (new DHTFindNodeReplyMessage + (family_, localNode_, remoteNode, transactionID)); m->setClosestKNodes(closestKNodes); setCommonProperty(m); return m; } -std::vector > -DHTMessageFactoryImpl::extractNodes(const unsigned char* src, size_t length) +void DHTMessageFactoryImpl::extractNodes +(std::vector >& nodes, + const unsigned char* src, size_t length) { - if(length%26 != 0) { - throw DL_ABORT_EX("Nodes length is not multiple of 26"); + int unit = bittorrent::getCompactLength(family_)+20; + if(length%unit != 0) { + throw DL_ABORT_EX + (StringFormat("Nodes length is not multiple of %d", unit).str()); } - std::vector > nodes; - for(size_t offset = 0; offset < length; offset += 26) { + for(size_t offset = 0; offset < length; offset += unit) { SharedHandle node(new DHTNode(src+offset)); std::pair addr = - bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH, AF_INET); + bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH, family_); if(addr.first.empty()) { continue; } @@ -373,7 +363,6 @@ DHTMessageFactoryImpl::extractNodes(const unsigned char* src, size_t length) node->setPort(addr.second); nodes.push_back(node); } - return nodes; } SharedHandle @@ -383,10 +372,13 @@ DHTMessageFactoryImpl::createFindNodeReplyMessage const std::string& transactionID) { const String* nodesData = - getString(getDictionary(dict, DHTResponseMessage::R), - DHTFindNodeReplyMessage::NODES); - std::vector > nodes = - extractNodes(nodesData->uc(), nodesData->s().size()); + asString(getDictionary(dict, DHTResponseMessage::R)-> + get(family_ == AF_INET?DHTFindNodeReplyMessage::NODES: + DHTFindNodeReplyMessage::NODES6)); + std::vector > nodes; + if(nodesData) { + extractNodes(nodes, nodesData->uc(), nodesData->s().size()); + } return createFindNodeReplyMessage(remoteNode, nodes, transactionID); } @@ -405,68 +397,55 @@ DHTMessageFactoryImpl::createGetPeersMessage } SharedHandle -DHTMessageFactoryImpl::createGetPeersReplyMessageWithNodes +DHTMessageFactoryImpl::createGetPeersReplyMessage (const SharedHandle& remoteNode, const Dict* dict, const std::string& transactionID) { const Dict* rDict = getDictionary(dict, DHTResponseMessage::R); - const String* nodesData = getString(rDict, DHTGetPeersReplyMessage::NODES); - std::vector > nodes = extractNodes - (nodesData->uc(), nodesData->s().size()); + const String* nodesData = + asString(rDict->get(family_ == AF_INET?DHTGetPeersReplyMessage::NODES: + DHTGetPeersReplyMessage::NODES6)); + std::vector > nodes; + if(nodesData) { + extractNodes(nodes, nodesData->uc(), nodesData->s().size()); + } + const List* valuesList = + asList(rDict->get(DHTGetPeersReplyMessage::VALUES)); + std::vector > 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 addr = + bittorrent::unpackcompact(data->uc(), family_); + if(addr.first.empty()) { + continue; + } + SharedHandle peer(new Peer(addr.first, addr.second)); + peers.push_back(peer); + } + } + } const String* token = getString(rDict, DHTGetPeersReplyMessage::TOKEN); return createGetPeersReplyMessage - (remoteNode, nodes, token->s(), transactionID); + (remoteNode, nodes, peers, token->s(), transactionID); } SharedHandle DHTMessageFactoryImpl::createGetPeersReplyMessage (const SharedHandle& remoteNode, const std::vector >& closestKNodes, - const std::string& token, - const std::string& transactionID) -{ - SharedHandle m - (new DHTGetPeersReplyMessage(localNode_, remoteNode, token, transactionID)); - m->setClosestKNodes(closestKNodes); - setCommonProperty(m); - return m; -} - -SharedHandle -DHTMessageFactoryImpl::createGetPeersReplyMessageWithValues -(const SharedHandle& remoteNode, - const Dict* dict, - const std::string& transactionID) -{ - const Dict* rDict = getDictionary(dict, DHTResponseMessage::R); - const List* valuesList = getList(rDict, - DHTGetPeersReplyMessage::VALUES); - std::vector > 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 addr = - bittorrent::unpackcompact(data->uc(), AF_INET); - SharedHandle 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 -DHTMessageFactoryImpl::createGetPeersReplyMessage -(const SharedHandle& remoteNode, const std::vector >& values, const std::string& token, const std::string& transactionID) { SharedHandle m - (new DHTGetPeersReplyMessage(localNode_, remoteNode, token, transactionID)); + (new DHTGetPeersReplyMessage + (family_, localNode_, remoteNode, token, transactionID)); + m->setClosestKNodes(closestKNodes); m->setValues(values); setCommonProperty(m); return m; diff --git a/src/DHTMessageFactoryImpl.h b/src/DHTMessageFactoryImpl.h index d7b639bf..f3e06895 100644 --- a/src/DHTMessageFactoryImpl.h +++ b/src/DHTMessageFactoryImpl.h @@ -51,6 +51,8 @@ class DHTAbstractMessage; class DHTMessageFactoryImpl:public DHTMessageFactory { private: + int family_; + SharedHandle localNode_; WeakHandle connection_; @@ -73,13 +75,14 @@ private: void validatePort(const Integer* i) const; - std::vector > - extractNodes(const unsigned char* src, size_t length); + void extractNodes + (std::vector >& nodes, + const unsigned char* src, size_t length); void setCommonProperty(const SharedHandle& m); public: - DHTMessageFactoryImpl(); + DHTMessageFactoryImpl(int family); virtual ~DHTMessageFactoryImpl(); @@ -127,25 +130,15 @@ public: createGetPeersReplyMessage (const SharedHandle& remoteNode, const std::vector >& closestKNodes, - const std::string& token, - const std::string& transactionID); - - SharedHandle - createGetPeersReplyMessageWithNodes(const SharedHandle& remoteNode, - const Dict* dict, - const std::string& transactionID); - - virtual SharedHandle - createGetPeersReplyMessage - (const SharedHandle& remoteNode, const std::vector >& peers, const std::string& token, const std::string& transactionID); SharedHandle - createGetPeersReplyMessageWithValues(const SharedHandle& remoteNode, - const Dict* dict, - const std::string& transactionID); + createGetPeersReplyMessage + (const SharedHandle& remoteNode, + const Dict* dict, + const std::string& transactionID); virtual SharedHandle createAnnouncePeerMessage(const SharedHandle& remoteNode, diff --git a/src/DHTMessageTracker.cc b/src/DHTMessageTracker.cc index ebbc8a9e..ed15f322 100644 --- a/src/DHTMessageTracker.cc +++ b/src/DHTMessageTracker.cc @@ -84,19 +84,24 @@ DHTMessageTracker::messageArrived logger_->debug("Tracker entry found."); } SharedHandle targetNode = entry->getTargetNode(); + try { + SharedHandle message = + factory_->createResponseMessage(entry->getMessageType(), dict, + targetNode->getIPAddress(), + targetNode->getPort()); - SharedHandle message = - factory_->createResponseMessage(entry->getMessageType(), dict, - targetNode->getIPAddress(), - targetNode->getPort()); - - int64_t rtt = entry->getElapsedMillis(); - if(logger_->debug()) { - logger_->debug("RTT is %s", util::itos(rtt).c_str()); + int64_t rtt = entry->getElapsedMillis(); + if(logger_->debug()) { + logger_->debug("RTT is %s", util::itos(rtt).c_str()); + } + message->getRemoteNode()->updateRTT(rtt); + SharedHandle callback = entry->getCallback(); + return std::make_pair(message, callback); + } catch(RecoverableException& e) { + entry->getCallback()->onTimeout(targetNode); + return std::pair, + SharedHandle >(); } - message->getRemoteNode()->updateRTT(rtt); - SharedHandle callback = entry->getCallback(); - return std::make_pair(message, callback); } } if(logger_->debug()) { diff --git a/src/DHTRegistry.cc b/src/DHTRegistry.cc index 909225e2..464f54f9 100644 --- a/src/DHTRegistry.cc +++ b/src/DHTRegistry.cc @@ -49,17 +49,30 @@ namespace aria2 { DHTRegistry::Data DHTRegistry::data_; +DHTRegistry::Data DHTRegistry::data6_; + +void DHTRegistry::clear(DHTRegistry::Data& data) +{ + data.initialized = false; + data.localNode.reset(); + data.routingTable.reset(); + data.taskQueue.reset(); + data.taskFactory.reset(); + data.peerAnnounceStorage.reset(); + data.tokenTracker.reset(); + data.messageDispatcher.reset(); + data.messageReceiver.reset(); + data.messageFactory.reset(); +} + void DHTRegistry::clearData() { - data_.localNode.reset(); - data_.routingTable.reset(); - data_.taskQueue.reset(); - data_.taskFactory.reset(); - data_.peerAnnounceStorage.reset(); - data_.tokenTracker.reset(); - data_.messageDispatcher.reset(); - data_.messageReceiver.reset(); - data_.messageFactory.reset(); + clear(data_); +} + +void DHTRegistry::clearData6() +{ + clear(data6_); } } // namespace aria2 diff --git a/src/DHTRegistry.h b/src/DHTRegistry.h index 5248d710..d3c13417 100644 --- a/src/DHTRegistry.h +++ b/src/DHTRegistry.h @@ -53,6 +53,8 @@ class DHTMessageFactory; class DHTRegistry { private: struct Data { + bool initialized; + SharedHandle localNode; SharedHandle routingTable; @@ -70,9 +72,15 @@ private: SharedHandle messageReceiver; SharedHandle messageFactory; + + Data():initialized(false) {} }; static Data data_; + static Data data6_; + + static void clear(Data& data); + DHTRegistry(); public: static const Data& getData() @@ -86,6 +94,38 @@ public: } static void clearData(); + + static bool isInitialized() + { + return data_.initialized; + } + + static void setInitialized(bool f) + { + data_.initialized = f; + } + + static const Data& getData6() + { + return data6_; + } + + static Data& getMutableData6() + { + return data6_; + } + + static void clearData6(); + + static bool isInitialized6() + { + return data6_.initialized; + } + + static void setInitialized6(bool f) + { + data6_.initialized = f; + } }; } // namespace aria2 diff --git a/src/DHTRoutingTableDeserializer.cc b/src/DHTRoutingTableDeserializer.cc index bed629ca..d06de4b3 100644 --- a/src/DHTRoutingTableDeserializer.cc +++ b/src/DHTRoutingTableDeserializer.cc @@ -52,7 +52,8 @@ namespace aria2 { -DHTRoutingTableDeserializer::DHTRoutingTableDeserializer() {} +DHTRoutingTableDeserializer::DHTRoutingTableDeserializer(int family): + family_(family) {} DHTRoutingTableDeserializer::~DHTRoutingTableDeserializer() {} @@ -99,7 +100,7 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in) headerCompat[6] = 0; headerCompat[7] = 0x02; - char zero[8]; + char zero[18]; memset(zero, 0, sizeof(zero)); int version; @@ -159,44 +160,39 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in) std::vector > nodes; // nodes + const int compactlen = bittorrent::getCompactLength(family_); for(size_t i = 0; i < numNodes; ++i) { - // Currently, only IPv4 addresses are supported. // 1byte compact peer info length uint8_t peerInfoLen; in >> peerInfoLen; - if(peerInfoLen != 6) { + if(peerInfoLen != compactlen) { // skip this entry - readBytes(buf, buf.size(), in, 42+7+6); - CHECK_STREAM(in, 42+7+6); + readBytes(buf, buf.size(), in, 7+48); + CHECK_STREAM(in, 7+48); continue; } // 7bytes reserved readBytes(buf, buf.size(), in, 7); CHECK_STREAM(in, 7); - // 6bytes compact peer info - readBytes(buf, buf.size(), in, 6); - CHECK_STREAM(in, 6); - if(memcmp(zero, buf, 6) == 0) { + // compactlen bytes compact peer info + readBytes(buf, buf.size(), in, compactlen); + CHECK_STREAM(in, compactlen); + if(memcmp(zero, buf, compactlen) == 0) { // skip this entry - readBytes(buf, buf.size(), in, 42); - CHECK_STREAM(in, 42); + readBytes(buf, buf.size(), in, 48-compactlen); + CHECK_STREAM(in, 48-compactlen); continue; } - // TODO DHT6 protocol family should be configurable. std::pair peer = - bittorrent::unpackcompact(buf, AF_INET); + bittorrent::unpackcompact(buf, family_); if(peer.first.empty()) { // skip this entry - readBytes(buf, buf.size(), in, 42); - CHECK_STREAM(in, 42); + readBytes(buf, buf.size(), in, 48-compactlen); + CHECK_STREAM(in, 48-compactlen); continue; } - // 2bytes reserved - readBytes(buf, buf.size(), in, 2); - CHECK_STREAM(in, 2); - // 16byte reserved - readBytes(buf, buf.size(), in, 16); - CHECK_STREAM(in, 16); + // 24-compactlen bytes reserved + readBytes(buf, buf.size(), in, 24-compactlen); // node ID readBytes(buf, buf.size(), in, DHT_ID_LENGTH); CHECK_STREAM(in, DHT_ID_LENGTH); diff --git a/src/DHTRoutingTableDeserializer.h b/src/DHTRoutingTableDeserializer.h index efa55a76..bd83fca4 100644 --- a/src/DHTRoutingTableDeserializer.h +++ b/src/DHTRoutingTableDeserializer.h @@ -49,13 +49,15 @@ class DHTNode; class DHTRoutingTableDeserializer { private: + int family_; + SharedHandle localNode_; std::vector > nodes_; Time serializedTime_; public: - DHTRoutingTableDeserializer(); + DHTRoutingTableDeserializer(int family); ~DHTRoutingTableDeserializer(); diff --git a/src/DHTRoutingTableSerializer.cc b/src/DHTRoutingTableSerializer.cc index 81976c50..d1bfa3f4 100644 --- a/src/DHTRoutingTableSerializer.cc +++ b/src/DHTRoutingTableSerializer.cc @@ -50,7 +50,8 @@ namespace aria2 { -DHTRoutingTableSerializer::DHTRoutingTableSerializer() {} +DHTRoutingTableSerializer::DHTRoutingTableSerializer(int family): + family_(family) {} DHTRoutingTableSerializer::~DHTRoutingTableSerializer() {} @@ -79,7 +80,7 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o) header[6] = 0; header[7] = 0x03; - char zero[16]; + char zero[18]; memset(zero, 0, sizeof(zero)); o.write(header, 8); @@ -101,29 +102,26 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o) // 4bytes reserved o.write(zero, 4); + const int clen = bittorrent::getCompactLength(family_); // nodes for(std::vector >::const_iterator i = nodes_.begin(), eoi = nodes_.end(); i != eoi; ++i) { const SharedHandle& node = *i; - // Currently, only IPv4 addresses are saved. - // 6bytes: write IP address + port in Compact IP-address/port info form. + // Write IP address + port in Compact IP-address/port info form. unsigned char compactPeer[COMPACT_LEN_IPV6]; int compactlen = bittorrent::packcompact (compactPeer, node->getIPAddress(), node->getPort()); - if(compactlen != COMPACT_LEN_IPV4) { - compactlen = COMPACT_LEN_IPV4; - memset(compactPeer, 0, COMPACT_LEN_IPV4); + if(compactlen != clen) { + memset(compactPeer, 0, clen); } // 1byte compact peer format length - o << static_cast(compactlen); + o << static_cast(clen); // 7bytes reserved o.write(zero, 7); - // 6 bytes compact peer - o.write(reinterpret_cast(compactPeer), compactlen); - // 2bytes reserved - o.write(zero, 2); - // 16bytes reserved - o.write(zero, 16); + // clen bytes compact peer + o.write(reinterpret_cast(compactPeer), clen); + // 24-clen bytes reserved + o.write(zero, 24-clen); // 20bytes: node ID o.write(reinterpret_cast(node->getID()), DHT_ID_LENGTH); // 4bytes reserved diff --git a/src/DHTRoutingTableSerializer.h b/src/DHTRoutingTableSerializer.h index 352bc08a..b2660518 100644 --- a/src/DHTRoutingTableSerializer.h +++ b/src/DHTRoutingTableSerializer.h @@ -48,11 +48,13 @@ class DHTNode; class DHTRoutingTableSerializer { private: + int family_; + SharedHandle localNode_; std::vector > nodes_; public: - DHTRoutingTableSerializer(); + DHTRoutingTableSerializer(int family); ~DHTRoutingTableSerializer(); diff --git a/src/DHTSetup.cc b/src/DHTSetup.cc index c6e623e8..ec8b7ac7 100644 --- a/src/DHTSetup.cc +++ b/src/DHTSetup.cc @@ -79,16 +79,18 @@ namespace aria2 { -// TODO DownloadEngine should hold this flag. -bool DHTSetup::initialized_ = false; - DHTSetup::DHTSetup():logger_(LogFactory::getInstance()) {} DHTSetup::~DHTSetup() {} -void DHTSetup::setup(std::vector& commands, DownloadEngine* e) +void DHTSetup::setup +(std::vector& commands, DownloadEngine* e, int family) { - if(initialized_) { + if(family != AF_INET && family != AF_INET6) { + return; + } + if((family == AF_INET && DHTRegistry::isInitialized()) || + (family == AF_INET6 && DHTRegistry::isInitialized6())) { return; } try { @@ -98,8 +100,10 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) SharedHandle localNode; - DHTRoutingTableDeserializer deserializer; - std::string dhtFile = e->getOption()->get(PREF_DHT_FILE_PATH); + DHTRoutingTableDeserializer deserializer(family); + const std::string& dhtFile = + e->getOption()->get(family == AF_INET?PREF_DHT_FILE_PATH: + PREF_DHT_FILE_PATH6); try { std::ifstream in(dhtFile.c_str(), std::ios::binary); if(!in) { @@ -115,12 +119,15 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) localNode.reset(new DHTNode()); } - SharedHandle connection(new DHTConnectionImpl()); + SharedHandle connection(new DHTConnectionImpl(family)); { IntSequence seq = util::parseIntRange(e->getOption()->get(PREF_DHT_LISTEN_PORT)); uint16_t port; - if(!connection->bind(port, seq)) { + const std::string& addr = + e->getOption()->get(family == AF_INET?PREF_DHT_LISTEN_ADDR: + PREF_DHT_LISTEN_ADDR6); + if(!connection->bind(port, addr, seq)) { throw DL_ABORT_EX("Error occurred while binding port for DHT"); } localNode->setPort(port); @@ -131,7 +138,8 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) } SharedHandle routingTable(new DHTRoutingTable(localNode)); - SharedHandle factory(new DHTMessageFactoryImpl()); + SharedHandle factory + (new DHTMessageFactoryImpl(family)); SharedHandle tracker(new DHTMessageTracker()); @@ -179,16 +187,27 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) factory->setLocalNode(localNode); // assign them into DHTRegistry - DHTRegistry::getMutableData().localNode = localNode; - DHTRegistry::getMutableData().routingTable = routingTable; - DHTRegistry::getMutableData().taskQueue = taskQueue; - DHTRegistry::getMutableData().taskFactory = taskFactory; - DHTRegistry::getMutableData().peerAnnounceStorage = peerAnnounceStorage; - DHTRegistry::getMutableData().tokenTracker = tokenTracker; - DHTRegistry::getMutableData().messageDispatcher = dispatcher; - DHTRegistry::getMutableData().messageReceiver = receiver; - DHTRegistry::getMutableData().messageFactory = factory; - + if(family == AF_INET) { + DHTRegistry::getMutableData().localNode = localNode; + DHTRegistry::getMutableData().routingTable = routingTable; + DHTRegistry::getMutableData().taskQueue = taskQueue; + DHTRegistry::getMutableData().taskFactory = taskFactory; + DHTRegistry::getMutableData().peerAnnounceStorage = peerAnnounceStorage; + DHTRegistry::getMutableData().tokenTracker = tokenTracker; + DHTRegistry::getMutableData().messageDispatcher = dispatcher; + DHTRegistry::getMutableData().messageReceiver = receiver; + DHTRegistry::getMutableData().messageFactory = factory; + } else { + DHTRegistry::getMutableData6().localNode = localNode; + DHTRegistry::getMutableData6().routingTable = routingTable; + DHTRegistry::getMutableData6().taskQueue = taskQueue; + DHTRegistry::getMutableData6().taskFactory = taskFactory; + DHTRegistry::getMutableData6().peerAnnounceStorage = peerAnnounceStorage; + DHTRegistry::getMutableData6().tokenTracker = tokenTracker; + DHTRegistry::getMutableData6().messageDispatcher = dispatcher; + DHTRegistry::getMutableData6().messageReceiver = receiver; + DHTRegistry::getMutableData6().messageFactory = factory; + } // add deserialized nodes to routing table const std::vector >& desnodes = deserializer.getNodes(); @@ -206,11 +225,16 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) taskQueue->addPeriodicTask1(task); } - if(!e->getOption()->get(PREF_DHT_ENTRY_POINT_HOST).empty()) { + const std::string& prefEntryPointHost = + family == AF_INET?PREF_DHT_ENTRY_POINT_HOST:PREF_DHT_ENTRY_POINT_HOST6; + if(!e->getOption()->get(prefEntryPointHost).empty()) { { + const std::string& prefEntryPointPort = + family == AF_INET?PREF_DHT_ENTRY_POINT_PORT: + PREF_DHT_ENTRY_POINT_PORT6; std::pair addr - (e->getOption()->get(PREF_DHT_ENTRY_POINT_HOST), - e->getOption()->getAsInt(PREF_DHT_ENTRY_POINT_PORT)); + (e->getOption()->get(prefEntryPointHost), + e->getOption()->getAsInt(prefEntryPointPort)); std::vector > entryPoints; entryPoints.push_back(addr); DHTEntryPointNameResolveCommand* command = @@ -258,24 +282,27 @@ void DHTSetup::setup(std::vector& commands, DownloadEngine* e) } { DHTAutoSaveCommand* command = - new DHTAutoSaveCommand(e->newCUID(), e, 30*60); + new DHTAutoSaveCommand(e->newCUID(), e, family, 30*60); command->setLocalNode(localNode); command->setRoutingTable(routingTable); tempCommands->push_back(command); } - initialized_ = true; + if(family == AF_INET) { + DHTRegistry::setInitialized(true); + } else { + DHTRegistry::setInitialized6(true); + } commands.insert(commands.end(), tempCommands->begin(), tempCommands->end()); tempCommands->clear(); } catch(RecoverableException& e) { logger_->error("Exception caught while initializing DHT functionality." " DHT is disabled.", e); - DHTRegistry::clearData(); + if(family == AF_INET) { + DHTRegistry::clearData(); + } else { + DHTRegistry::clearData6(); + } } } -bool DHTSetup::initialized() -{ - return initialized_; -} - } // namespace aria2 diff --git a/src/DHTSetup.h b/src/DHTSetup.h index ca932554..08d5cdd7 100644 --- a/src/DHTSetup.h +++ b/src/DHTSetup.h @@ -45,18 +45,13 @@ class Command; class DHTSetup { private: - static bool initialized_; - Logger* logger_; - public: DHTSetup(); ~DHTSetup(); - void setup(std::vector& commands, DownloadEngine* e); - - static bool initialized(); + void setup(std::vector& commands, DownloadEngine* e, int family); }; } // namespace aria2 diff --git a/src/FtpConnection.cc b/src/FtpConnection.cc index d0b22e33..6dbdcb5e 100644 --- a/src/FtpConnection.cc +++ b/src/FtpConnection.cc @@ -223,7 +223,7 @@ SharedHandle FtpConnection::createServerSocket() std::pair addrinfo; socket_->getAddrInfo(addrinfo); SharedHandle serverSocket(new SocketCore()); - serverSocket->bind(addrinfo.first, 0); + serverSocket->bind(addrinfo.first, 0, AF_UNSPEC); serverSocket->beginListen(); serverSocket->setNonBlockingMode(); return serverSocket; diff --git a/src/LpdMessageReceiver.cc b/src/LpdMessageReceiver.cc index 81256bad..4935d6fa 100644 --- a/src/LpdMessageReceiver.cc +++ b/src/LpdMessageReceiver.cc @@ -56,7 +56,7 @@ bool LpdMessageReceiver::init(const std::string& localAddr) // Binding multicast address fails under Windows. socket_->bindWithFamily(multicastPort_, AF_INET); #else // !__MINGW32__ - socket_->bind(multicastAddress_, multicastPort_); + socket_->bind(multicastAddress_, multicastPort_, AF_INET); #endif // !__MINGW32__ if(logger_->debug()) { logger_->debug("Joining multicast group. %s:%u, localAddr=%s", diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 52dafb22..7766ef0a 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -1325,6 +1325,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_BITTORRENT); handlers.push_back(op); } + { + SharedHandle 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 op(new DefaultOptionHandler (PREF_DHT_FILE_PATH, @@ -1334,6 +1344,34 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_BITTORRENT); handlers.push_back(op); } + { + SharedHandle 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 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 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 op(new IntegerRangeOptionHandler (PREF_DHT_LISTEN_PORT, @@ -1363,6 +1401,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_BITTORRENT); handlers.push_back(op); } + { + SharedHandle 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 op(new BooleanOptionHandler (PREF_ENABLE_PEER_EXCHANGE, diff --git a/src/OptionHandlerImpl.h b/src/OptionHandlerImpl.h index a1d63c90..b39578d5 100644 --- a/src/OptionHandlerImpl.h +++ b/src/OptionHandlerImpl.h @@ -522,17 +522,18 @@ public: virtual void parseArg(Option& option, const std::string& optarg) { - std::pair proxy = util::split(optarg, ":"); - int32_t port = util::parseInt(proxy.second); - if(proxy.first.empty() || proxy.second.empty() || - port <= 0 || 65535 < port) { - throw DL_ABORT_EX(_("unrecognized proxy format")); + std::string uri = "http://"; + uri += optarg; + Request req; + if(!req.setUri(uri)) { + throw DL_ABORT_EX(_("Unrecognized format")); } option.put(optName_, optarg); - setHostAndPort(option, proxy.first, port); + setHostAndPort(option, req.getHost(), req.getPort()); } - void setHostAndPort(Option& option, const std::string& hostname, uint16_t port) + void setHostAndPort + (Option& option, const std::string& hostname, uint16_t port) { option.put(hostOptionName_, hostname); option.put(portOptionName_, util::uitos(port)); diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 87d4b1c9..31c8f57a 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -60,8 +60,13 @@ #include "DHTTaskQueue.h" #include "DHTTaskFactory.h" #include "DHTNode.h" -#include "DHTSetup.h" #include "DHTRegistry.h" +#include "DHTPeerAnnounceStorage.h" +#include "DHTTokenTracker.h" +#include "DHTMessageDispatcher.h" +#include "DHTMessageReceiver.h" +#include "DHTMessageFactory.h" +#include "DHTMessageCallback.h" #include "PieceStorage.h" #include "RequestGroup.h" #include "BtAnnounce.h" @@ -102,6 +107,17 @@ PeerInteractionCommand::PeerInteractionCommand setWriteCheckSocket(getSocket()); setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); } + + int family; + unsigned char compact[COMPACT_LEN_IPV6]; + int compactlen = bittorrent::packcompact + (compact, getPeer()->getIPAddress(), getPeer()->getPort()); + if(compactlen == COMPACT_LEN_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + SharedHandle torrentAttrs = bittorrent::getTorrentAttrs(requestGroup_->getDownloadContext()); bool metadataGetMode = torrentAttrs->metadata.empty(); @@ -131,11 +147,18 @@ PeerInteractionCommand::PeerInteractionCommand factory->setPieceStorage(pieceStorage); factory->setPeerStorage(peerStorage); factory->setExtensionMessageFactory(extensionMessageFactory); - factory->setPeer(getPeer()); - factory->setLocalNode(DHTRegistry::getData().localNode); - factory->setRoutingTable(DHTRegistry::getData().routingTable); - factory->setTaskQueue(DHTRegistry::getData().taskQueue); - factory->setTaskFactory(DHTRegistry::getData().taskFactory); + factory->setPeer(getPeer()); + if(family == AF_INET) { + factory->setLocalNode(DHTRegistry::getData().localNode); + factory->setRoutingTable(DHTRegistry::getData().routingTable); + factory->setTaskQueue(DHTRegistry::getData().taskQueue); + factory->setTaskFactory(DHTRegistry::getData().taskFactory); + } else { + factory->setLocalNode(DHTRegistry::getData6().localNode); + factory->setRoutingTable(DHTRegistry::getData6().routingTable); + factory->setTaskQueue(DHTRegistry::getData6().taskQueue); + factory->setTaskFactory(DHTRegistry::getData6().taskFactory); + } if(metadataGetMode) { factory->enableMetadataGetMode(); } @@ -192,10 +215,18 @@ PeerInteractionCommand::PeerInteractionCommand if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { btInteractive->setUTPexEnabled(true); } - if(DHTSetup::initialized()) { - btInteractive->setDHTEnabled(true); - btInteractive->setLocalNode(DHTRegistry::getData().localNode); - factory->setDHTEnabled(true); + if(family == AF_INET) { + if(DHTRegistry::isInitialized()) { + btInteractive->setDHTEnabled(true); + factory->setDHTEnabled(true); + btInteractive->setLocalNode(DHTRegistry::getData().localNode); + } + } else { + if(DHTRegistry::isInitialized6()) { + btInteractive->setDHTEnabled(true); + factory->setDHTEnabled(true); + btInteractive->setLocalNode(DHTRegistry::getData6().localNode); + } } } btInteractive->setUTMetadataRequestFactory(utMetadataRequestFactory); diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 42d65bd0..c5606e16 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -94,6 +94,15 @@ # include "BtPostDownloadHandler.h" # include "DHTSetup.h" # include "DHTRegistry.h" +# include "DHTNode.h" +# include "DHTRoutingTable.h" +# include "DHTTaskQueue.h" +# include "DHTTaskFactory.h" +# include "DHTTokenTracker.h" +# include "DHTMessageDispatcher.h" +# include "DHTMessageReceiver.h" +# include "DHTMessageFactory.h" +# include "DHTMessageCallback.h" # include "BtMessageFactory.h" # include "BtRequestFactory.h" # include "BtMessageDispatcher.h" @@ -283,10 +292,18 @@ void RequestGroup::createInitialCommand SharedHandle (progressInfoFile)))); if(metadataGetMode) { - if(option_->getAsBool(PREF_ENABLE_DHT)) { - std::vector dhtCommands; - DHTSetup().setup(dhtCommands, e); - e->addCommand(dhtCommands); + if(option_->getAsBool(PREF_ENABLE_DHT) || + option_->getAsBool(PREF_ENABLE_DHT6)) { + if(option_->getAsBool(PREF_ENABLE_DHT)) { + std::vector dhtCommands; + DHTSetup().setup(dhtCommands, e, AF_INET); + e->addCommand(dhtCommands); + } + if(option_->getAsBool(PREF_ENABLE_DHT6)) { + std::vector dhtCommands; + DHTSetup().setup(dhtCommands, e, AF_INET6); + e->addCommand(dhtCommands); + } } else { logger_->notice("For BitTorrent Magnet URI, enabling DHT is strongly" " recommended. See --enable-dht option."); @@ -343,16 +360,25 @@ void RequestGroup::createInitialCommand } progressInfoFile_ = progressInfoFile; - if(!torrentAttrs->privateTorrent && option_->getAsBool(PREF_ENABLE_DHT)) { - std::vector dhtCommands; - DHTSetup().setup(dhtCommands, e); - e->addCommand(dhtCommands); + if(!torrentAttrs->privateTorrent && + (option_->getAsBool(PREF_ENABLE_DHT) || + option_->getAsBool(PREF_ENABLE_DHT6))) { + if(option_->getAsBool(PREF_ENABLE_DHT)) { + std::vector dhtCommands; + DHTSetup().setup(dhtCommands, e, AF_INET); + e->addCommand(dhtCommands); + } + if(option_->getAsBool(PREF_ENABLE_DHT6)) { + std::vector dhtCommands; + DHTSetup().setup(dhtCommands, e, AF_INET6); + e->addCommand(dhtCommands); + } const std::vector >& nodes = torrentAttrs->nodes; - if(!nodes.empty() && DHTSetup::initialized()) { - std::vector > entryPoints(nodes); + // TODO Are nodes in torrent IPv4 only? + if(!nodes.empty() && DHTRegistry::isInitialized()) { DHTEntryPointNameResolveCommand* command = - new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints); + new DHTEntryPointNameResolveCommand(e->newCUID(), e, nodes); command->setTaskQueue(DHTRegistry::getData().taskQueue); command->setTaskFactory(DHTRegistry::getData().taskFactory); command->setRoutingTable(DHTRegistry::getData().routingTable); diff --git a/src/SocketCore.cc b/src/SocketCore.cc index 7d8b076b..a445b35c 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -54,6 +54,7 @@ #include "TimeA2.h" #include "a2functional.h" #include "LogFactory.h" +#include "A2STR.h" #ifdef ENABLE_SSL # include "TLSContext.h" #endif // ENABLE_SSL @@ -215,6 +216,14 @@ static sock_t bindInternal(int family, int socktype, int protocol, CLOSE(fd); return -1; } + if(family == AF_INET6) { + int sockopt = 1; + if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (a2_sockopt_t) &sockopt, + sizeof(sockopt)) < 0) { + CLOSE(fd); + return -1; + } + } if(::bind(fd, addr, addrlen) == -1) { error = errorMsg(); CLOSE(fd); @@ -258,25 +267,19 @@ void SocketCore::bindWithFamily(uint16_t port, int family, int flags) } } -void SocketCore::bind(const std::string& addr, uint16_t port, int flags) +void SocketCore::bind +(const std::string& addr, uint16_t port, int family, int flags) { closeConnection(); std::string error; - sock_t fd = - bindTo(addr.c_str(), port, protocolFamily_, sockType_, flags, error); - if(fd == (sock_t)-1) { - throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, error.c_str()).str()); + const char* addrp; + if(addr.empty()) { + addrp = 0; } else { - sockfd_ = fd; + addrp = addr.c_str(); } -} - -void SocketCore::bind(uint16_t port, int flags) -{ - closeConnection(); - std::string error; if(!(flags&AI_PASSIVE) || bindAddrs_.empty()) { - sock_t fd = bindTo(0, port, protocolFamily_, sockType_, flags, error); + sock_t fd = bindTo(addrp, port, family, sockType_, flags, error); if(fd != (sock_t) -1) { sockfd_ = fd; } @@ -294,7 +297,11 @@ void SocketCore::bind(uint16_t port, int flags) error = gai_strerror(s); continue; } - sock_t fd = bindTo(host, port, protocolFamily_, sockType_, flags, error); + if(addrp && strcmp(host, addrp) != 0) { + // TODO we should assign something to error? + continue; + } + sock_t fd = bindTo(addrp, port, family, sockType_, flags, error); if(fd != (sock_t)-1) { sockfd_ = fd; break; @@ -306,6 +313,11 @@ void SocketCore::bind(uint16_t port, int flags) } } +void SocketCore::bind(uint16_t port, int flags) +{ + bind(A2STR::NIL, port, protocolFamily_, flags); +} + void SocketCore::bind(const struct sockaddr* addr, socklen_t addrlen) { closeConnection(); diff --git a/src/SocketCore.h b/src/SocketCore.h index 7de5a0eb..3ea31b87 100644 --- a/src/SocketCore.h +++ b/src/SocketCore.h @@ -137,8 +137,6 @@ public: void bindWithFamily(uint16_t port, int family, int flags = AI_PASSIVE); - void bind(const std::string& addr, uint16_t port, int flags = AI_PASSIVE); - /** * Creates a socket and bind it with locahost's address and port. * flags is set to struct addrinfo's ai_flags. @@ -147,6 +145,9 @@ public: */ void bind(uint16_t port, int flags = AI_PASSIVE); + void bind + (const std::string& addr, uint16_t port, int family, int flags = AI_PASSIVE); + /** * Listens form connection on it. * Call bind(uint16_t) before calling this function. diff --git a/src/bittorrent_helper.cc b/src/bittorrent_helper.cc index 7b342aa9..6801e95e 100644 --- a/src/bittorrent_helper.cc +++ b/src/bittorrent_helper.cc @@ -994,6 +994,17 @@ std::string torrent2Magnet(const SharedHandle& attrs) return uri; } +int getCompactLength(int family) +{ + if(family == AF_INET) { + return COMPACT_LEN_IPV4; + } else if(family == AF_INET6) { + return COMPACT_LEN_IPV6; + } else { + return 0; + } +} + } // namespace bittorrent } // namespace aria2 diff --git a/src/bittorrent_helper.h b/src/bittorrent_helper.h index 8d890b5b..cf9a40f5 100644 --- a/src/bittorrent_helper.h +++ b/src/bittorrent_helper.h @@ -246,6 +246,9 @@ void extractPeer(const ValueBase* peerData, int family, OutputIterator dest) const unsigned char* end = base+length; for(; base != end; base += unit) { std::pair p = unpackcompact(base, family_); + if(p.first.empty()) { + continue; + } *dest_++ = SharedHandle(new Peer(p.first, p.second)); } } @@ -288,6 +291,8 @@ void extractPeer return extractPeer(peerData.get(), family, dest); } +int getCompactLength(int family); + } // namespace bittorrent } // namespace aria2 diff --git a/src/prefs.cc b/src/prefs.cc index 2712fb48..a11ac8ad 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -308,6 +308,8 @@ const std::string PREF_PEER_ID_PREFIX("peer-id-prefix"); const std::string PREF_ENABLE_PEER_EXCHANGE("enable-peer-exchange"); // values: true | false const std::string PREF_ENABLE_DHT("enable-dht"); +// values: a string +const std::string PREF_DHT_LISTEN_ADDR("dht-listen-addr"); // values: 1*digit const std::string PREF_DHT_LISTEN_PORT("dht-listen-port"); // values: a string @@ -318,6 +320,18 @@ const std::string PREF_DHT_ENTRY_POINT_PORT("dht-entry-point-port"); const std::string PREF_DHT_ENTRY_POINT("dht-entry-point"); // values: a string const std::string PREF_DHT_FILE_PATH("dht-file-path"); +// values: true | false +const std::string PREF_ENABLE_DHT6("enable-dht6"); +// values: a string +const std::string PREF_DHT_LISTEN_ADDR6("dht-listen-addr6"); +// values: a string +const std::string PREF_DHT_ENTRY_POINT_HOST6("dht-entry-point-host6"); +// values: 1*digit +const std::string PREF_DHT_ENTRY_POINT_PORT6("dht-entry-point-port6"); +// values: a string (hostname:port) +const std::string PREF_DHT_ENTRY_POINT6("dht-entry-point6"); +// values: a string +const std::string PREF_DHT_FILE_PATH6("dht-file-path6"); // values: plain | arc4 const std::string PREF_BT_MIN_CRYPTO_LEVEL("bt-min-crypto-level"); const std::string V_PLAIN("plain"); diff --git a/src/prefs.h b/src/prefs.h index 34193d9c..d49d4556 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -312,6 +312,8 @@ extern const std::string PREF_PEER_ID_PREFIX; extern const std::string PREF_ENABLE_PEER_EXCHANGE; // values: true | false extern const std::string PREF_ENABLE_DHT; +// values: a string +extern const std::string PREF_DHT_LISTEN_ADDR; // values: 1*digit extern const std::string PREF_DHT_LISTEN_PORT; // values: a string @@ -322,6 +324,18 @@ extern const std::string PREF_DHT_ENTRY_POINT_PORT; extern const std::string PREF_DHT_ENTRY_POINT; // values: a string extern const std::string PREF_DHT_FILE_PATH; +// values: true | false +extern const std::string PREF_ENABLE_DHT6; +// values: a string +extern const std::string PREF_DHT_LISTEN_ADDR6; +// values: a string +extern const std::string PREF_DHT_ENTRY_POINT_HOST6; +// values: 1*digit +extern const std::string PREF_DHT_ENTRY_POINT_PORT6; +// values: a string (hostname:port) +extern const std::string PREF_DHT_ENTRY_POINT6; +// values: a string +extern const std::string PREF_DHT_FILE_PATH6; // values: plain | arc4 extern const std::string PREF_BT_MIN_CRYPTO_LEVEL; extern const std::string V_PLAIN; diff --git a/src/usage_text.h b/src/usage_text.h index 6eb97ee2..6c805c01 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -297,18 +297,18 @@ #define TEXT_ENABLE_PEER_EXCHANGE \ _(" --enable-peer-exchange[=true|false] Enable Peer Exchange extension.") #define TEXT_ENABLE_DHT \ - _(" --enable-dht[=true|false] Enable DHT functionality.") + _(" --enable-dht[=true|false] Enable IPv4 DHT functionality.") #define TEXT_DHT_LISTEN_PORT \ - _(" --dht-listen-port=PORT... Set UDP listening port for DHT.\n" \ - " Multiple ports can be specified by using ',',\n" \ - " for example: \"6881,6885\". You can also use '-'\n" \ - " to specify a range: \"6881-6999\". ',' and '-' can\n" \ - " be used together.") + _(" --dht-listen-port=PORT... Set UDP listening port for both IPv4 and IPv6\n" \ + " DHT. Multiple ports can be specified by using\n" \ + " ',', for example: \"6881,6885\". You can also\n" \ + " use '-' to specify a range: \"6881-6999\". ','\n" \ + " and '-' can be used together.") #define TEXT_DHT_ENTRY_POINT \ - _(" --dht-entry-point=HOST:PORT Set host and port as an entry point to DHT\n" \ + _(" --dht-entry-point=HOST:PORT Set host and port as an entry point to IPv4 DHT\n" \ " network.") #define TEXT_DHT_FILE_PATH \ - _(" --dht-file-path=PATH Change the DHT routing table file to PATH.") + _(" --dht-file-path=PATH Change the IPv4 DHT routing table file to PATH.") #define TEXT_BT_MIN_CRYPTO_LEVEL \ _(" --bt-min-crypto-level=plain|arc4 Set minimum level of encryption method.\n" \ " If several encryption methods are provided by a\n" \ @@ -714,3 +714,15 @@ _(" --enable-async-dns6[=true|false] Enable IPv6 name resolution in asynchronous\n" \ " DNS resolver. This option will be ignored when\n" \ " --async-dns=false.") +#define TEXT_ENABLE_DHT6 \ + _(" --enable-dht6[=true|false] Enable IPv6 DHT functionality. See also\n" \ + " --dht-listen-addr6 option.") +#define TEXT_DHT_LISTEN_ADDR6 \ + _(" --dht-listen-addr6=ADDR Specify address to bind socket for IPv6 DHT. \n" \ + " It should be a global unicast IPv6 address of the\n" \ + " host.") +#define TEXT_DHT_ENTRY_POINT6 \ + _(" --dht-entry-point6=HOST:PORT Set host and port as an entry point to IPv6 DHT\n" \ + " network.") +#define TEXT_DHT_FILE_PATH6 \ + _(" --dht-file-path6=PATH Change the IPv6 DHT routing table file to PATH.") diff --git a/test/DHTConnectionImplTest.cc b/test/DHTConnectionImplTest.cc index 15a66a16..2e24ef31 100644 --- a/test/DHTConnectionImplTest.cc +++ b/test/DHTConnectionImplTest.cc @@ -1,9 +1,12 @@ #include "DHTConnectionImpl.h" -#include "Exception.h" -#include "SocketCore.h" + #include #include +#include "Exception.h" +#include "SocketCore.h" +#include "A2STR.h" + namespace aria2 { class DHTConnectionImplTest:public CppUnit::TestFixture { @@ -25,13 +28,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DHTConnectionImplTest); void DHTConnectionImplTest::testWriteAndReadData() { try { - DHTConnectionImpl con1; + DHTConnectionImpl con1(AF_INET); uint16_t con1port = 0; - CPPUNIT_ASSERT(con1.bind(con1port)); + CPPUNIT_ASSERT(con1.bind(con1port, A2STR::NIL)); - DHTConnectionImpl con2; + DHTConnectionImpl con2(AF_INET); uint16_t con2port = 0; - CPPUNIT_ASSERT(con2.bind(con2port)); + CPPUNIT_ASSERT(con2.bind(con2port, A2STR::NIL)); std::string message1 = "hello world."; // hostname should be "localhost", not 127.0.0.1. Test failed on Mac OSX10.5 diff --git a/test/DHTFindNodeReplyMessageTest.cc b/test/DHTFindNodeReplyMessageTest.cc index 1191e279..7a15b445 100644 --- a/test/DHTFindNodeReplyMessageTest.cc +++ b/test/DHTFindNodeReplyMessageTest.cc @@ -15,6 +15,7 @@ class DHTFindNodeReplyMessageTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DHTFindNodeReplyMessageTest); CPPUNIT_TEST(testGetBencodedMessage); + CPPUNIT_TEST(testGetBencodedMessage6); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} @@ -22,6 +23,8 @@ public: void tearDown() {} void testGetBencodedMessage(); + + void testGetBencodedMessage6(); }; @@ -36,7 +39,7 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage() util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH); std::string transactionID(&tid[0], &tid[DHT_TRANSACTION_ID_LENGTH]); - DHTFindNodeReplyMessage msg(localNode, remoteNode, transactionID); + DHTFindNodeReplyMessage msg(AF_INET, localNode, remoteNode, transactionID); msg.setVersion("A200"); std::string compactNodeInfo; SharedHandle nodes[8]; @@ -46,8 +49,8 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage() nodes[i]->setPort(6881+i); unsigned char buf[COMPACT_LEN_IPV6]; - bittorrent::packcompact - (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()); + CPPUNIT_ASSERT_EQUAL(COMPACT_LEN_IPV4, bittorrent::packcompact + (buf, nodes[i]->getIPAddress(), nodes[i]->getPort())); compactNodeInfo += std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+ std::string(&buf[0], &buf[COMPACT_LEN_IPV4]); @@ -69,4 +72,46 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage() CPPUNIT_ASSERT_EQUAL(bencode2::encode(&dict), msgbody); } +void DHTFindNodeReplyMessageTest::testGetBencodedMessage6() +{ + SharedHandle localNode(new DHTNode()); + SharedHandle 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 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 >(&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 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 diff --git a/test/DHTGetPeersMessageTest.cc b/test/DHTGetPeersMessageTest.cc index 9a817cbf..11a280c1 100644 --- a/test/DHTGetPeersMessageTest.cc +++ b/test/DHTGetPeersMessageTest.cc @@ -31,24 +31,11 @@ public: class MockDHTMessageFactory2:public MockDHTMessageFactory { public: - virtual SharedHandle - createGetPeersReplyMessage(const SharedHandle& remoteNode, - const std::vector >& peers, - const std::string& token, - const std::string& transactionID) - { - SharedHandle m - (new MockDHTResponseMessage - (localNode_, remoteNode, "get_peers", transactionID)); - m->peers_ = peers; - m->token_ = token; - return m; - } - virtual SharedHandle createGetPeersReplyMessage (const SharedHandle& remoteNode, const std::vector >& closestKNodes, + const std::vector >& peers, const std::string& token, const std::string& transactionID) { @@ -56,10 +43,10 @@ public: (new MockDHTResponseMessage (localNode_, remoteNode, "get_peers", transactionID)); m->nodes_ = closestKNodes; + m->peers_ = peers; m->token_ = token; return m; } - }; }; @@ -115,14 +102,13 @@ void DHTGetPeersMessageTest::testDoReceivedAction() MockDHTMessageDispatcher dispatcher; MockDHTMessageFactory2 factory; factory.setLocalNode(localNode); + DHTRoutingTable routingTable(localNode); DHTGetPeersMessage msg(localNode, remoteNode, infoHash, transactionID); - msg.setTokenTracker(WeakHandle - (&tokenTracker)); - msg.setMessageDispatcher(WeakHandle - (&dispatcher)); - msg.setMessageFactory(WeakHandle - (&factory)); + msg.setRoutingTable(WeakHandle(&routingTable)); + msg.setTokenTracker(WeakHandle(&tokenTracker)); + msg.setMessageDispatcher(WeakHandle(&dispatcher)); + msg.setMessageFactory(WeakHandle(&factory)); { // localhost has peer contact information for that infohash. DHTPeerAnnounceStorage peerAnnounceStorage; diff --git a/test/DHTGetPeersReplyMessageTest.cc b/test/DHTGetPeersReplyMessageTest.cc index 1eff779e..064a2bd5 100644 --- a/test/DHTGetPeersReplyMessageTest.cc +++ b/test/DHTGetPeersReplyMessageTest.cc @@ -16,6 +16,7 @@ class DHTGetPeersReplyMessageTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DHTGetPeersReplyMessageTest); CPPUNIT_TEST(testGetBencodedMessage); + CPPUNIT_TEST(testGetBencodedMessage6); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} @@ -23,6 +24,8 @@ public: void tearDown() {} void testGetBencodedMessage(); + + void testGetBencodedMessage6(); }; @@ -39,7 +42,8 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage() std::string token = "token"; - DHTGetPeersReplyMessage msg(localNode, remoteNode, token, transactionID); + DHTGetPeersReplyMessage msg + (AF_INET, localNode, remoteNode, token, transactionID); msg.setVersion("A200"); Dict dict; dict.put("t", transactionID); @@ -58,38 +62,97 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage() nodes[i]->setPort(6881+i); unsigned char buf[COMPACT_LEN_IPV6]; - bittorrent::packcompact - (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()); + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV4, + bittorrent::packcompact + (buf, nodes[i]->getIPAddress(), nodes[i]->getPort())); compactNodeInfo += std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+ std::string(&buf[0], &buf[COMPACT_LEN_IPV4]); } msg.setClosestKNodes (std::vector >(&nodes[0], &nodes[DHTBucket::K])); - - std::string msgbody = msg.getBencodedMessage(); - rDict->put("nodes", compactNodeInfo); - CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)), - util::percentEncode(msgbody)); - } - rDict->removeKey("nodes"); - { std::vector > peers; SharedHandle valuesList = List::g(); for(size_t i = 0; i < 4; ++i) { SharedHandle peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i)); unsigned char buffer[COMPACT_LEN_IPV6]; - bittorrent::packcompact(buffer, peer->getIPAddress(), peer->getPort()); + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV4, + bittorrent::packcompact + (buffer, peer->getIPAddress(), peer->getPort())); valuesList->append(String::g(buffer, COMPACT_LEN_IPV4)); peers.push_back(peer); } + msg.setValues(peers); rDict->put("values", valuesList); - msg.setValues(peers); - std::string msgbody = msg.getBencodedMessage(); + std::string msgbody = msg.getBencodedMessage(); + CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)), + util::percentEncode(msgbody)); + } +} +void DHTGetPeersReplyMessageTest::testGetBencodedMessage6() +{ + SharedHandle localNode(new DHTNode()); + SharedHandle 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 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 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 >(&nodes[0], &nodes[DHTBucket::K])); + rDict->put("nodes6", compactNodeInfo); + + std::vector > peers; + SharedHandle valuesList = List::g(); + for(size_t i = 0; i < 4; ++i) { + SharedHandle peer(new Peer("2001::100"+util::uitos(i+1), 6881+i)); + unsigned char buffer[COMPACT_LEN_IPV6]; + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV6, + bittorrent::packcompact + (buffer, peer->getIPAddress(), peer->getPort())); + valuesList->append(String::g(buffer, COMPACT_LEN_IPV6)); + peers.push_back(peer); + } + msg.setValues(peers); + rDict->put("values", valuesList); + + std::string msgbody = msg.getBencodedMessage(); CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)), util::percentEncode(msgbody)); } diff --git a/test/DHTMessageFactoryImplTest.cc b/test/DHTMessageFactoryImplTest.cc index 6210c27a..04bd2ff5 100644 --- a/test/DHTMessageFactoryImplTest.cc +++ b/test/DHTMessageFactoryImplTest.cc @@ -31,9 +31,10 @@ class DHTMessageFactoryImplTest:public CppUnit::TestFixture { CPPUNIT_TEST(testCreatePingReplyMessage); CPPUNIT_TEST(testCreateFindNodeMessage); CPPUNIT_TEST(testCreateFindNodeReplyMessage); + CPPUNIT_TEST(testCreateFindNodeReplyMessage6); CPPUNIT_TEST(testCreateGetPeersMessage); - CPPUNIT_TEST(testCreateGetPeersReplyMessage_nodes); - CPPUNIT_TEST(testCreateGetPeersReplyMessage_values); + CPPUNIT_TEST(testCreateGetPeersReplyMessage); + CPPUNIT_TEST(testCreateGetPeersReplyMessage6); CPPUNIT_TEST(testCreateAnnouncePeerMessage); CPPUNIT_TEST(testCreateAnnouncePeerReplyMessage); CPPUNIT_TEST(testReceivedErrorMessage); @@ -52,7 +53,7 @@ public: void setUp() { localNode.reset(new DHTNode()); - factory.reset(new DHTMessageFactoryImpl()); + factory.reset(new DHTMessageFactoryImpl(AF_INET)); factory->setLocalNode(localNode); memset(transactionID, 0xff, DHT_TRANSACTION_ID_LENGTH); memset(remoteNodeID, 0x0f, DHT_ID_LENGTH); @@ -66,9 +67,10 @@ public: void testCreatePingReplyMessage(); void testCreateFindNodeMessage(); void testCreateFindNodeReplyMessage(); + void testCreateFindNodeReplyMessage6(); void testCreateGetPeersMessage(); - void testCreateGetPeersReplyMessage_nodes(); - void testCreateGetPeersReplyMessage_values(); + void testCreateGetPeersReplyMessage(); + void testCreateGetPeersReplyMessage6(); void testCreateAnnouncePeerMessage(); void testCreateAnnouncePeerReplyMessage(); void testReceivedErrorMessage(); @@ -169,8 +171,10 @@ void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage() nodes[i]->setPort(6881+i); unsigned char buf[COMPACT_LEN_IPV6]; - bittorrent::packcompact - (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()); + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV4, + bittorrent::packcompact + (buf, nodes[i]->getIPAddress(), nodes[i]->getPort())); compactNodeInfo += std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+ std::string(&buf[0], &buf[COMPACT_LEN_IPV4]); @@ -200,6 +204,58 @@ void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage() } } +void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage6() +{ + factory.reset(new DHTMessageFactoryImpl(AF_INET6)); + factory->setLocalNode(localNode); + factory->setRoutingTable(routingTable); + try { + Dict dict; + dict.put("t", String::g(transactionID, DHT_TRANSACTION_ID_LENGTH)); + dict.put("y", "r"); + SharedHandle rDict = Dict::g(); + rDict->put("id", String::g(remoteNodeID, DHT_ID_LENGTH)); + std::string compactNodeInfo; + SharedHandle 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 remoteNode(new DHTNode(remoteNodeID)); + remoteNode->setIPAddress("2001::2001"); + remoteNode->setPort(6881); + + SharedHandle m + (dynamic_pointer_cast + (factory->createResponseMessage("find_node", &dict, + remoteNode->getIPAddress(), + remoteNode->getPort()))); + + CPPUNIT_ASSERT(localNode == m->getLocalNode()); + CPPUNIT_ASSERT(remoteNode == m->getRemoteNode()); + CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size()); + CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]); + CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]); + CPPUNIT_ASSERT_EQUAL(util::toHex(transactionID, DHT_TRANSACTION_ID_LENGTH), + util::toHex(m->getTransactionID())); + } catch(Exception& e) { + CPPUNIT_FAIL(e.stackTrace()); + } +} + void DHTMessageFactoryImplTest::testCreateGetPeersMessage() { Dict dict; @@ -228,7 +284,7 @@ void DHTMessageFactoryImplTest::testCreateGetPeersMessage() util::toHex(m->getInfoHash(), DHT_ID_LENGTH)); } -void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes() +void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage() { try { Dict dict; @@ -244,13 +300,30 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes() nodes[i]->setPort(6881+i); unsigned char buf[COMPACT_LEN_IPV6]; - bittorrent::packcompact - (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()); + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV4, + bittorrent::packcompact + (buf, nodes[i]->getIPAddress(), nodes[i]->getPort())); compactNodeInfo += std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+ std::string(&buf[0], &buf[COMPACT_LEN_IPV4]); } rDict->put("nodes", compactNodeInfo); + + std::deque > peers; + SharedHandle valuesList = List::g(); + for(size_t i = 0; i < 4; ++i) { + SharedHandle peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i)); + unsigned char buffer[COMPACT_LEN_IPV6]; + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV4, + bittorrent::packcompact + (buffer, peer->getIPAddress(), peer->getPort())); + valuesList->append(String::g(buffer, COMPACT_LEN_IPV4)); + peers.push_back(peer); + } + rDict->put("values", valuesList); + rDict->put("token", "token"); dict.put("r", rDict); @@ -270,6 +343,9 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes() CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size()); CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]); CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]); + CPPUNIT_ASSERT_EQUAL((size_t)4, m->getValues().size()); + CPPUNIT_ASSERT(peers[0] == m->getValues()[0]); + CPPUNIT_ASSERT(peers[3] == m->getValues()[3]); CPPUNIT_ASSERT_EQUAL(util::toHex(transactionID, DHT_TRANSACTION_ID_LENGTH), util::toHex(m->getTransactionID())); } catch(Exception& e) { @@ -277,31 +353,54 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes() } } -void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_values() +void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage6() { + factory.reset(new DHTMessageFactoryImpl(AF_INET6)); + factory->setLocalNode(localNode); + factory->setRoutingTable(routingTable); try { Dict dict; dict.put("t", String::g(transactionID, DHT_TRANSACTION_ID_LENGTH)); dict.put("y", "r"); SharedHandle rDict = Dict::g(); rDict->put("id", String::g(remoteNodeID, DHT_ID_LENGTH)); + std::string compactNodeInfo; + SharedHandle 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 > peers; SharedHandle valuesList = List::g(); for(size_t i = 0; i < 4; ++i) { - SharedHandle peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i)); + SharedHandle peer(new Peer("2001::100"+util::uitos(i+1), 6881+i)); unsigned char buffer[COMPACT_LEN_IPV6]; - bittorrent::packcompact - (buffer, peer->getIPAddress(), peer->getPort()); - valuesList->append(String::g(buffer, COMPACT_LEN_IPV4)); + CPPUNIT_ASSERT_EQUAL + (COMPACT_LEN_IPV6, + bittorrent::packcompact + (buffer, peer->getIPAddress(), peer->getPort())); + valuesList->append(String::g(buffer, COMPACT_LEN_IPV6)); peers.push_back(peer); } rDict->put("values", valuesList); + rDict->put("token", "token"); dict.put("r", rDict); SharedHandle remoteNode(new DHTNode(remoteNodeID)); - remoteNode->setIPAddress("192.168.0.1"); + remoteNode->setIPAddress("2001::2001"); remoteNode->setPort(6881); SharedHandle m @@ -313,6 +412,9 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_values() CPPUNIT_ASSERT(localNode == m->getLocalNode()); CPPUNIT_ASSERT(remoteNode == m->getRemoteNode()); CPPUNIT_ASSERT_EQUAL(std::string("token"), m->getToken()); + CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size()); + CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]); + CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]); CPPUNIT_ASSERT_EQUAL((size_t)4, m->getValues().size()); CPPUNIT_ASSERT(peers[0] == m->getValues()[0]); CPPUNIT_ASSERT(peers[3] == m->getValues()[3]); diff --git a/test/DHTRoutingTableDeserializerTest.cc b/test/DHTRoutingTableDeserializerTest.cc index 7f2c8d7e..fcd737c4 100644 --- a/test/DHTRoutingTableDeserializerTest.cc +++ b/test/DHTRoutingTableDeserializerTest.cc @@ -20,6 +20,7 @@ class DHTRoutingTableDeserializerTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DHTRoutingTableDeserializerTest); CPPUNIT_TEST(testDeserialize); + CPPUNIT_TEST(testDeserialize6); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} @@ -27,6 +28,8 @@ public: void tearDown() {} void testDeserialize(); + + void testDeserialize6(); }; @@ -45,14 +48,14 @@ void DHTRoutingTableDeserializerTest::testDeserialize() nodesSrc[1]->setIPAddress("non-numerical-name"); std::vector > nodes(vbegin(nodesSrc), vend(nodesSrc)); - DHTRoutingTableSerializer s; + DHTRoutingTableSerializer s(AF_INET); s.setLocalNode(localNode); s.setNodes(nodes); std::stringstream ss; s.serialize(ss); - DHTRoutingTableDeserializer d; + DHTRoutingTableDeserializer d(AF_INET); d.deserialize(ss); CPPUNIT_ASSERT(memcmp(localNode->getID(), d.getLocalNode()->getID(), @@ -70,4 +73,44 @@ void DHTRoutingTableDeserializerTest::testDeserialize() CPPUNIT_ASSERT(memcmp(nodes[2]->getID(), dsnodes[1]->getID(), DHT_ID_LENGTH) == 0); } +void DHTRoutingTableDeserializerTest::testDeserialize6() +{ + SharedHandle localNode(new DHTNode()); + + SharedHandle 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 > 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 >& 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 diff --git a/test/DHTRoutingTableSerializerTest.cc b/test/DHTRoutingTableSerializerTest.cc index 81450a6b..3523e341 100644 --- a/test/DHTRoutingTableSerializerTest.cc +++ b/test/DHTRoutingTableSerializerTest.cc @@ -20,42 +20,35 @@ class DHTRoutingTableSerializerTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DHTRoutingTableSerializerTest); CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST(testSerialize6); CPPUNIT_TEST_SUITE_END(); +private: + char zero[256]; + char buf[20]; + + void checkToLocalnode + (std::istream& ss, const SharedHandle& localNode); + + void checkNumNodes(std::istream& ss, size_t expected); public: - void setUp() {} + void setUp() + { + memset(zero, 0, sizeof(zero)); + } void tearDown() {} void testSerialize(); + + void testSerialize6(); }; CPPUNIT_TEST_SUITE_REGISTRATION(DHTRoutingTableSerializerTest); -void DHTRoutingTableSerializerTest::testSerialize() +void DHTRoutingTableSerializerTest::checkToLocalnode +(std::istream& ss, const SharedHandle& localNode) { - SharedHandle localNode(new DHTNode()); - - SharedHandle 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 > nodes(vbegin(nodesSrc), vend(nodesSrc)); - - DHTRoutingTableSerializer s; - s.setLocalNode(localNode); - s.setNodes(nodes); - - std::stringstream ss; - s.serialize(ss); - - char zero[16]; - memset(zero, 0, sizeof(zero)); - - char buf[20]; // header ss.read(buf, 8); // magic @@ -89,14 +82,44 @@ void DHTRoutingTableSerializerTest::testSerialize() // 4bytes reserved ss.read(buf, 4); CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0); +} +void DHTRoutingTableSerializerTest::checkNumNodes +(std::istream& ss, size_t expected) +{ // number of nodes saved ss.read(buf, 4); uint32_t numNodes; memcpy(&numNodes, buf, sizeof(numNodes)); numNodes = ntohl(numNodes); - CPPUNIT_ASSERT_EQUAL((uint32_t)3, numNodes); + CPPUNIT_ASSERT_EQUAL((uint32_t)expected, numNodes); +} + +void DHTRoutingTableSerializerTest::testSerialize() +{ + SharedHandle localNode(new DHTNode()); + + SharedHandle 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 > nodes(vbegin(nodesSrc), vend(nodesSrc)); + + DHTRoutingTableSerializer s(AF_INET); + s.setLocalNode(localNode); + s.setNodes(nodes); + + std::stringstream ss; + s.serialize(ss); + + checkToLocalnode(ss, localNode); + size_t numNodes = 3; + checkNumNodes(ss, numNodes); + // 4bytes reserved ss.read(buf, 4); CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0); @@ -199,4 +222,92 @@ void DHTRoutingTableSerializerTest::testSerialize() CPPUNIT_ASSERT(ss.eof()); } +void DHTRoutingTableSerializerTest::testSerialize6() +{ + SharedHandle localNode(new DHTNode()); + + SharedHandle 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 > 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 peer = + bittorrent::unpackcompact(reinterpret_cast(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 diff --git a/test/LpdMessageDispatcherTest.cc b/test/LpdMessageDispatcherTest.cc index 598178c6..3324bf84 100644 --- a/test/LpdMessageDispatcherTest.cc +++ b/test/LpdMessageDispatcherTest.cc @@ -46,7 +46,7 @@ void LpdMessageDispatcherTest::testSendMessage() #ifdef __MINGW32__ recvsock->bindWithFamily(LPD_MULTICAST_PORT, AF_INET); #else // !__MINGW32__ - recvsock->bind(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + recvsock->bind(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, AF_INET); #endif // !__MINGW32__ recvsock->joinMulticastGroup(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, ""); diff --git a/test/MockDHTMessageFactory.h b/test/MockDHTMessageFactory.h index efb83b52..7382bd69 100644 --- a/test/MockDHTMessageFactory.h +++ b/test/MockDHTMessageFactory.h @@ -81,18 +81,9 @@ public: createGetPeersReplyMessage (const SharedHandle& remoteNode, const std::vector >& closestKNodes, - const std::string& token, - const std::string& transactionID) - { - return SharedHandle(); - } - - - virtual SharedHandle - createGetPeersReplyMessage(const SharedHandle& remoteNode, - const std::vector >& peers, - const std::string& token, - const std::string& transactionID) + const std::vector >& peers, + const std::string& token, + const std::string& transactionID) { return SharedHandle(); }