Sfoglia il codice sorgente

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

	Added bittorrent::packcompact() which replaces
	bittorrent::createcompact() and supports IPv6 addresses. Rewritten
	bittorrent::unpackcompact() and bittorrent::extractPeer() to
	support IPv6 addresses. Fixed added.f flags in ut_pex.
	* src/BtConstants.h
	* src/DHTFindNodeReplyMessage.cc
	* src/DHTGetPeersReplyMessage.cc
	* src/DHTMessageFactoryImpl.cc
	* src/DHTRoutingTableDeserializer.cc
	* src/DHTRoutingTableSerializer.cc
	* src/DHTTokenTracker.cc
	* src/DefaultBtAnnounce.cc
	* src/UTPexExtensionMessage.cc
	* src/bittorrent_helper.cc
	* src/bittorrent_helper.h
	* test/BittorrentHelperTest.cc
	* test/DHTFindNodeReplyMessageTest.cc
	* test/DHTGetPeersReplyMessageTest.cc
	* test/DHTMessageFactoryImplTest.cc
	* test/DHTRoutingTableSerializerTest.cc
	* test/DefaultExtensionMessageFactoryTest.cc
	* test/UTPexExtensionMessageTest.cc
Tatsuhiro Tsujikawa 15 anni fa
parent
commit
2bd5020f81

+ 25 - 0
ChangeLog

@@ -1,3 +1,28 @@
+2010-08-03  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added bittorrent::packcompact() which replaces
+	bittorrent::createcompact() and supports IPv6 addresses. Rewritten
+	bittorrent::unpackcompact() and bittorrent::extractPeer() to
+	support IPv6 addresses. Fixed added.f flags in ut_pex.
+	* src/BtConstants.h
+	* src/DHTFindNodeReplyMessage.cc
+	* src/DHTGetPeersReplyMessage.cc
+	* src/DHTMessageFactoryImpl.cc
+	* src/DHTRoutingTableDeserializer.cc
+	* src/DHTRoutingTableSerializer.cc
+	* src/DHTTokenTracker.cc
+	* src/DefaultBtAnnounce.cc
+	* src/UTPexExtensionMessage.cc
+	* src/bittorrent_helper.cc
+	* src/bittorrent_helper.h
+	* test/BittorrentHelperTest.cc
+	* test/DHTFindNodeReplyMessageTest.cc
+	* test/DHTGetPeersReplyMessageTest.cc
+	* test/DHTMessageFactoryImplTest.cc
+	* test/DHTRoutingTableSerializerTest.cc
+	* test/DefaultExtensionMessageFactoryTest.cc
+	* test/UTPexExtensionMessageTest.cc
+
 2010-08-01  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Added --enable-async-dns6 option. This option enables IPv6 name

+ 4 - 0
src/BtConstants.h

@@ -62,4 +62,8 @@ typedef std::map<std::string, uint8_t> Extensions;
 
 #define LPD_MULTICAST_PORT 6771
 
+#define COMPACT_LEN_IPV4 6
+
+#define COMPACT_LEN_IPV6 18
+
 #endif // _D_BT_CONSTANTS_

+ 5 - 2
src/DHTFindNodeReplyMessage.cc

@@ -81,8 +81,11 @@ SharedHandle<Dict> DHTFindNodeReplyMessage::getResponse()
       i != eoi && offset < DHTBucket::K*26; ++i) {
     SharedHandle<DHTNode> node = *i;
     memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
-    if(bittorrent::createcompact(buffer+20+offset, node->getIPAddress(),
-                                 node->getPort())) {
+    unsigned char compact[COMPACT_LEN_IPV6];
+    int compactlen = bittorrent::packcompact
+      (compact, node->getIPAddress(), node->getPort());
+    if(compactlen == COMPACT_LEN_IPV4) {
+      memcpy(buffer+20+offset, compact, compactlen);
       offset += 26;
     }
   }

+ 10 - 6
src/DHTGetPeersReplyMessage.cc

@@ -85,8 +85,11 @@ SharedHandle<Dict> DHTGetPeersReplyMessage::getResponse()
         i != eoi && offset < DHTBucket::K*26; ++i) {
       SharedHandle<DHTNode> node = *i;
       memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
-      if(bittorrent::createcompact
-         (buffer+20+offset, node->getIPAddress(), node->getPort())) {
+      unsigned char compact[COMPACT_LEN_IPV6];
+      int compactlen = bittorrent::packcompact
+        (compact, node->getIPAddress(), node->getPort());
+      if(compactlen == COMPACT_LEN_IPV4) {
+        memcpy(buffer+20+offset, compact, compactlen);
         offset += 26;
       }
     }
@@ -117,10 +120,11 @@ SharedHandle<Dict> DHTGetPeersReplyMessage::getResponse()
           eoi = values_.end(); i != eoi && valuesList->size() < MAX_VALUES_SIZE;
         ++i) {
       const SharedHandle<Peer>& peer = *i;
-      unsigned char buffer[6];
-      if(bittorrent::createcompact
-         (buffer, peer->getIPAddress(), peer->getPort())) {
-        valuesList->append(String::g(buffer, sizeof(buffer)));
+      unsigned char compact[COMPACT_LEN_IPV6];
+      int compactlen = bittorrent::packcompact
+        (compact, peer->getIPAddress(), peer->getPort());
+      if(compactlen == COMPACT_LEN_IPV4) {
+        valuesList->append(String::g(compact, compactlen));
       }
     }
     rDict->put(VALUES, valuesList);

+ 2 - 2
src/DHTMessageFactoryImpl.cc

@@ -365,7 +365,7 @@ DHTMessageFactoryImpl::extractNodes(const unsigned char* src, size_t length)
   for(size_t offset = 0; offset < length; offset += 26) {
     SharedHandle<DHTNode> node(new DHTNode(src+offset));
     std::pair<std::string, uint16_t> addr =
-      bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH);
+      bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH, AF_INET);
     if(addr.first.empty()) {
       continue;
     }
@@ -448,7 +448,7 @@ DHTMessageFactoryImpl::createGetPeersReplyMessageWithValues
     const String* data = asString(*i);
     if(data && data->s().size() == 6) {
       std::pair<std::string, uint16_t> addr =
-        bittorrent::unpackcompact(data->uc());
+        bittorrent::unpackcompact(data->uc(), AF_INET);
       SharedHandle<Peer> peer(new Peer(addr.first, addr.second));
       peers.push_back(peer);
     }

+ 3 - 1
src/DHTRoutingTableDeserializer.cc

@@ -182,7 +182,9 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in)
       CHECK_STREAM(in, 42);
       continue;
     }
-    std::pair<std::string, uint16_t> peer = bittorrent::unpackcompact(buf);
+    // TODO DHT6 protocol family should be configurable.
+    std::pair<std::string, uint16_t> peer =
+      bittorrent::unpackcompact(buf, AF_INET);
     if(peer.first.empty()) {
       // skip this entry
       readBytes(buf, buf.size(), in, 42);

+ 9 - 7
src/DHTRoutingTableSerializer.cc

@@ -105,19 +105,21 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o)
   for(std::vector<SharedHandle<DHTNode> >::const_iterator i = nodes_.begin(),
         eoi = nodes_.end(); i != eoi; ++i) {
     const SharedHandle<DHTNode>& node = *i;
-    // Currently, only IPv4 address and IPv4-mapped address are saved.
+    // Currently, only IPv4 addresses are saved.
     // 6bytes: write IP address + port in Compact IP-address/port info form.
-    unsigned char compactPeer[6];
-    if(!bittorrent::createcompact
-       (compactPeer, node->getIPAddress(), node->getPort())) {
-      memset(compactPeer, 0, 6);
+    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);
     }
     // 1byte compact peer format length
-    o << static_cast<uint8_t>(sizeof(compactPeer));
+    o << static_cast<uint8_t>(compactlen);
     // 7bytes reserved
     o.write(zero, 7);
     // 6 bytes compact peer
-    o.write(reinterpret_cast<const char*>(compactPeer), 6);
+    o.write(reinterpret_cast<const char*>(compactPeer), compactlen);
     // 2bytes reserved
     o.write(zero, 2);
     // 16bytes reserved

+ 11 - 7
src/DHTTokenTracker.cc

@@ -59,20 +59,24 @@ DHTTokenTracker::DHTTokenTracker(const unsigned char* initialSecret)
 
 DHTTokenTracker::~DHTTokenTracker() {}
 
-std::string DHTTokenTracker::generateToken(const unsigned char* infoHash,
-                                           const std::string& ipaddr, uint16_t port,
-                                           const unsigned char* secret) const
+std::string DHTTokenTracker::generateToken
+(const unsigned char* infoHash,
+ const std::string& ipaddr, uint16_t port,
+ const unsigned char* secret) const
 {
-  unsigned char src[DHT_ID_LENGTH+6+SECRET_SIZE];
-  if(!bittorrent::createcompact(src+DHT_ID_LENGTH, ipaddr, port)) {
+  unsigned char src[DHT_ID_LENGTH+COMPACT_LEN_IPV6+SECRET_SIZE];
+  memset(src, 0, sizeof(src));
+  int compactlen = bittorrent::packcompact(src+DHT_ID_LENGTH, ipaddr, port);
+  if(compactlen == 0) {
     throw DL_ABORT_EX
       (StringFormat("Token generation failed: ipaddr=%s, port=%u",
                     ipaddr.c_str(), port).str());
   }
   memcpy(src, infoHash, DHT_ID_LENGTH);
-  memcpy(src+DHT_ID_LENGTH+6, secret, SECRET_SIZE);
+  memcpy(src+DHT_ID_LENGTH+COMPACT_LEN_IPV6, secret, SECRET_SIZE);
   unsigned char md[20];
-  MessageDigestHelper::digest(md, sizeof(md), MessageDigestContext::SHA1, src, sizeof(src));
+  MessageDigestHelper::digest(md, sizeof(md), MessageDigestContext::SHA1,
+                              src, sizeof(src));
   return std::string(&md[0], &md[sizeof(md)]);
 }
 

+ 1 - 1
src/DefaultBtAnnounce.cc

@@ -276,7 +276,7 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
   } else {
     if(!btRuntime_->isHalt() && btRuntime_->lessThanMinPeers()) {
       std::vector<SharedHandle<Peer> > peers;
-      bittorrent::extractPeer(peerData, std::back_inserter(peers));
+      bittorrent::extractPeer(peerData, AF_INET, std::back_inserter(peers));
       peerStorage_->addPeer(peers);
     }
   }

+ 10 - 7
src/UTPexExtensionMessage.cc

@@ -78,11 +78,12 @@ UTPexExtensionMessage::createCompactPeerListAndFlag
   std::string flagstring;
   for(std::vector<SharedHandle<Peer> >::const_iterator itr = peers.begin(),
         eoi = peers.end(); itr != eoi; ++itr) {
-    unsigned char compact[6];
-    if(bittorrent::createcompact
-       (compact, (*itr)->getIPAddress(), (*itr)->getPort())) {
-      addrstring.append(&compact[0], &compact[6]);
-      flagstring += (*itr)->isSeeder() ? "2" : "0";
+    unsigned char compact[COMPACT_LEN_IPV6];
+    int compactlen = bittorrent::packcompact
+      (compact, (*itr)->getIPAddress(), (*itr)->getPort());
+    if(compactlen == COMPACT_LEN_IPV4) {
+      addrstring.append(&compact[0], &compact[compactlen]);
+      flagstring += (*itr)->isSeeder() ? 0x02 : 0x00;
     }
   }
   return std::pair<std::string, std::string>(addrstring, flagstring);
@@ -162,11 +163,13 @@ UTPexExtensionMessage::create(const unsigned char* data, size_t len)
   if(dict) {
     const String* added = asString(dict->get("added"));
     if(added) {
-      bittorrent::extractPeer(added, std::back_inserter(msg->freshPeers_));
+      bittorrent::extractPeer
+        (added, AF_INET,  std::back_inserter(msg->freshPeers_));
     }
     const String* dropped = asString(dict->get("dropped"));
     if(dropped) {
-      bittorrent::extractPeer(dropped, std::back_inserter(msg->droppedPeers_));
+      bittorrent::extractPeer
+        (dropped, AF_INET, std::back_inserter(msg->droppedPeers_));
     }
   }
   return msg;

+ 43 - 41
src/bittorrent_helper.cc

@@ -54,6 +54,7 @@
 #include "magnet.h"
 #include "bencode2.h"
 #include "TorrentAttribute.h"
+#include "SocketCore.h"
 
 namespace aria2 {
 
@@ -623,8 +624,9 @@ void computeFastSet
 (std::vector<size_t>& fastSet, const std::string& ipaddr,
  size_t numPieces, const unsigned char* infoHash, size_t fastSetSize)
 {
-  unsigned char compact[6];
-  if(!createcompact(compact, ipaddr, 0)) {
+  unsigned char compact[COMPACT_LEN_IPV6];
+  int compactlen = packcompact(compact, ipaddr, 0);
+  if(compactlen != COMPACT_LEN_IPV4) {
     return;
   }
   if(numPieces < fastSetSize) {
@@ -801,50 +803,50 @@ void createPeerMessageString
   msg[4] = messageId;
 }
 
-bool createcompact
+int packcompact
 (unsigned char* compact, const std::string& addr, uint16_t port)
 {
-  struct addrinfo hints;
   struct addrinfo* res;
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = AF_INET; // since compact peer format is ipv4 only.
-  hints.ai_flags = AI_NUMERICHOST;
-  if(getaddrinfo(addr.c_str(), 0, &hints, &res)) {
-    return false;
-  }
-  struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(res->ai_addr);
-  memcpy(compact, &(in->sin_addr.s_addr), sizeof(uint32_t));
-  uint16_t port_nworder(htons(port));
-  memcpy(compact+4, &port_nworder, sizeof(uint16_t));
-  freeaddrinfo(res);
-  return true;
-}
-
-std::pair<std::string, uint16_t> unpackcompact(const unsigned char* compact)
-{
-  struct sockaddr_in in;
-  memset(&in, 0, sizeof(in));
-#ifdef HAVE_SOCKADDR_IN_SIN_LEN
-  // For netbsd
-  in.sin_len = sizeof(in);
-#endif // HAVE_SOCKADDR_IN_SIN_LEN
-  in.sin_family = AF_INET;
-  memcpy(&(in.sin_addr.s_addr), compact, sizeof(uint32_t));
-  in.sin_port = 0;
-  char host[NI_MAXHOST];
-  int s;
-  s = getnameinfo(reinterpret_cast<const struct sockaddr*>(&in), sizeof(in),
-                  host, NI_MAXHOST, 0, 0,
-                  NI_NUMERICHOST);
-  if(s) {
-    return std::pair<std::string, uint16_t>();
-  }
-  uint16_t port_nworder;
-  memcpy(&port_nworder, compact+sizeof(uint32_t), sizeof(uint16_t));
-  uint16_t port = ntohs(port_nworder);
-  return std::make_pair(host, port);
+  int s =
+    callGetaddrinfo(&res, addr.c_str(), 0, AF_UNSPEC, 0, AI_NUMERICHOST, 0);
+  if(s != 0) {
+    return 0;
+  }
+  WSAAPI_AUTO_DELETE<struct addrinfo*> resDeleter(res, freeaddrinfo);
+  uint16_t portN = htons(port);
+  for(struct addrinfo* rp = res; rp; rp = rp->ai_next) {
+    if(rp->ai_family == AF_INET) {
+      struct sockaddr_in* in =
+        reinterpret_cast<struct sockaddr_in*>(res->ai_addr);
+      memcpy(compact, &(in->sin_addr), 4);
+      memcpy(compact+4, &portN, sizeof(portN));
+      return COMPACT_LEN_IPV4;
+    } else if(rp->ai_family == AF_INET6) {
+      struct sockaddr_in6* in6 =
+        reinterpret_cast<struct sockaddr_in6*>(res->ai_addr);
+      memcpy(compact, &(in6->sin6_addr), 16);
+      memcpy(compact+16, &portN, sizeof(portN));
+      return COMPACT_LEN_IPV6;
+    }
+  }
+  return 0;
 }
 
+std::pair<std::string, uint16_t> unpackcompact
+(const unsigned char* compact, int family)
+{
+  int portOffset = family == AF_INET?4:16;
+  std::pair<std::string, uint16_t> r;
+  char buf[INET6_ADDRSTRLEN];
+  if(!inet_ntop(family, compact, buf, sizeof(buf))) {
+    return r;
+  }
+  r.first = buf;
+  uint16_t portN;
+  memcpy(&portN, compact+portOffset, sizeof(portN));
+  r.second = ntohs(portN);
+  return r;
+}
 
 void assertPayloadLengthGreater
 (size_t threshold, size_t actual, const std::string& msgName)

+ 33 - 25
src/bittorrent_helper.h

@@ -182,18 +182,25 @@ void createPeerMessageString
 (unsigned char* msg, size_t msgLength, size_t payloadLength, uint8_t messageId);
 
 /**
- * Creates compact tracker format(6bytes for ipv4 address and port)
- * and stores the results in compact.
- * compact must be at least 6 bytes and pre-allocated.
- * Returns true if creation is successful, otherwise returns false.
- * The example of failure reason is that addr is not numbers-and-dots
- * notation.
+ * Creates compact form(packed addresss + 2bytes port) and stores the
+ * results in compact.  This function looks addr and if it is IPv4
+ * address, it stores 6bytes in compact and if it is IPv6, it stores
+ * 18bytes in compact.  So compact must be at least 18 bytes and
+ * pre-allocated.  Returns the number of written bytes; for IPv4
+ * address, it is 6 and for IPv6, it is 18. On failure, returns 0.
  */
-bool createcompact
+int packcompact
 (unsigned char* compact, const std::string& addr, uint16_t port);
 
-// Unpack compact into pair of IPv4 address and port.
-std::pair<std::string, uint16_t> unpackcompact(const unsigned char* compact);
+/**
+ * Unpack packed address and port in compact and returns address and
+ * port pair.  family must be AF_INET or AF_INET6.  If family is
+ * AF_INET, first 6 bytes from compact is used.  If family is
+ * AF_INET6, first 18 bytes from compact is used.  On failure, returns
+ * std::pair<std::string, uint16_t>().
+ */
+std::pair<std::string, uint16_t>
+unpackcompact(const unsigned char* compact, int family);
 
 // Throws exception if threshold >= actual
 void assertPayloadLengthGreater
@@ -216,30 +223,30 @@ std::string metadata2Torrent
 std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs);
 
 template<typename OutputIterator>
-void extractPeer(const ValueBase* peerData, OutputIterator dest)
+void extractPeer(const ValueBase* peerData, int family, OutputIterator dest)
 {
   class PeerListValueBaseVisitor:public ValueBaseVisitor {
   private:
     OutputIterator dest_;
+    int family_;
   public:
-    PeerListValueBaseVisitor(OutputIterator dest):dest_(dest) {}
+    PeerListValueBaseVisitor(OutputIterator dest, int family):
+      dest_(dest),
+      family_(family) {}
 
     virtual ~PeerListValueBaseVisitor() {}
 
     virtual void visit(const String& peerData)
     {
+      int unit = family_ == AF_INET?6:18;
       size_t length = peerData.s().size();
-      if(length%6 == 0) {
-        const char* base = peerData.s().data();
-        for(size_t i = 0; i < length; i += 6) {
-          struct in_addr in;
-          memcpy(&in.s_addr, base+i, sizeof(uint32_t));
-          std::string ipaddr = inet_ntoa(in);
-          uint16_t port_nworder;
-          memcpy(&port_nworder, base+i+4, sizeof(uint16_t));
-          uint16_t port = ntohs(port_nworder);
-          *dest_ = SharedHandle<Peer>(new Peer(ipaddr, port));
-          ++dest_;
+      if(length%unit == 0) {
+        const unsigned char* base =
+          reinterpret_cast<const unsigned char*>(peerData.s().data());
+        const unsigned char* end = base+length;
+        for(; base != end; base += unit) {
+          std::pair<std::string, uint16_t> p = unpackcompact(base, family_);
+          *dest_++ = SharedHandle<Peer>(new Peer(p.first, p.second));
         }
       }
     }
@@ -269,15 +276,16 @@ void extractPeer(const ValueBase* peerData, OutputIterator dest)
     virtual void visit(const Dict& v) {}
   };
   if(peerData) {
-    PeerListValueBaseVisitor visitor(dest);
+    PeerListValueBaseVisitor visitor(dest, family);
     peerData->accept(visitor);
   }
 }
 
 template<typename OutputIterator>
-void extractPeer(const SharedHandle<ValueBase>& peerData, OutputIterator dest)
+void extractPeer
+(const SharedHandle<ValueBase>& peerData, int family, OutputIterator dest)
 {
-  return extractPeer(peerData.get(), dest);
+  return extractPeer(peerData.get(), family, dest);
 }
 
 } // namespace bittorrent

+ 71 - 16
test/BittorrentHelperTest.cc

@@ -56,15 +56,17 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testSetFileFilter_multi);
   CPPUNIT_TEST(testUTF8Torrent);
   CPPUNIT_TEST(testEtc);
-  CPPUNIT_TEST(testCreatecompact);
   CPPUNIT_TEST(testCheckBitfield);
   CPPUNIT_TEST(testMetadata);
   CPPUNIT_TEST(testParseMagnet);
   CPPUNIT_TEST(testParseMagnet_base32);
   CPPUNIT_TEST(testMetadata2Torrent);
   CPPUNIT_TEST(testTorrent2Magnet);
+  CPPUNIT_TEST(testExtractPeerFromString);
   CPPUNIT_TEST(testExtractPeerFromList);
   CPPUNIT_TEST(testExtract2PeersFromList);
+  CPPUNIT_TEST(testPackcompact);
+  CPPUNIT_TEST(testUnpackcompact);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {
@@ -101,15 +103,17 @@ public:
   void testSetFileFilter_multi();
   void testUTF8Torrent();
   void testEtc();
-  void testCreatecompact();
   void testCheckBitfield();
   void testMetadata();
   void testParseMagnet();
   void testParseMagnet_base32();
   void testMetadata2Torrent();
   void testTorrent2Magnet();
+  void testExtractPeerFromString();
   void testExtractPeerFromList();
   void testExtract2PeersFromList();
+  void testPackcompact();
+  void testUnpackcompact();
 };
 
 
@@ -645,18 +649,6 @@ void BittorrentHelperTest::testEtc()
                        getTorrentAttrs(dctx)->creationDate);
 }
 
-void BittorrentHelperTest::testCreatecompact()
-{
-  unsigned char compact[6];
-  // Note: bittorrent::createcompact() on linux can handle IPv4-mapped
-  // addresses like `ffff::127.0.0.1', but on cygwin, it doesn't.
-  CPPUNIT_ASSERT(createcompact(compact, "127.0.0.1", 6881));
-
-  std::pair<std::string, uint16_t> p = unpackcompact(compact);
-  CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), p.first);
-  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, p.second);
-}
-
 void BittorrentHelperTest::testCheckBitfield()
 {
   unsigned char bitfield[] = { 0xff, 0xe0 };
@@ -760,6 +752,35 @@ void BittorrentHelperTest::testTorrent2Magnet()
      torrent2Magnet(getTorrentAttrs(dctx)));
 }
 
+void BittorrentHelperTest::testExtractPeerFromString()
+{
+  std::string hextext = "100210354527354678541237324732171ae1";
+  hextext += "20010db8bd0501d2288a1fc0000110ee1ae2";
+  std::string peersstr = "36:"+util::fromHex(hextext);
+  SharedHandle<ValueBase> str = bencode2::decode(peersstr);
+  std::deque<SharedHandle<Peer> > peers;
+  extractPeer(str, AF_INET6, std::back_inserter(peers));
+  CPPUNIT_ASSERT_EQUAL((size_t)2, peers.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("1002:1035:4527:3546:7854:1237:3247:3217"),
+                       peers[0]->getIPAddress());
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, peers[0]->getPort());
+  CPPUNIT_ASSERT_EQUAL(std::string("2001:db8:bd05:1d2:288a:1fc0:1:10ee"),
+                       peers[1]->getIPAddress());
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6882, peers[1]->getPort());
+
+  hextext = "c0a800011ae1";
+  hextext += "c0a800021ae2";
+  peersstr = "12:"+util::fromHex(hextext);
+  str = bencode2::decode(peersstr);
+  peers.clear();
+  extractPeer(str, AF_INET, std::back_inserter(peers));
+  CPPUNIT_ASSERT_EQUAL((size_t)2, peers.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), peers[0]->getIPAddress());
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, peers[0]->getPort());
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), peers[1]->getIPAddress());
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6882, peers[1]->getPort()); 
+}
+
 void BittorrentHelperTest::testExtractPeerFromList()
 {
   std::string peersString =
@@ -769,7 +790,7 @@ void BittorrentHelperTest::testExtractPeerFromList()
   SharedHandle<ValueBase> dict = bencode2::decode(peersString);
   
   std::deque<SharedHandle<Peer> > peers;
-  extractPeer(asDict(dict)->get("peers"), std::back_inserter(peers));
+  extractPeer(asDict(dict)->get("peers"), AF_INET, std::back_inserter(peers));
   CPPUNIT_ASSERT_EQUAL((size_t)1, peers.size());
   SharedHandle<Peer> peer = *peers.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), peer->getIPAddress());
@@ -786,7 +807,7 @@ void BittorrentHelperTest::testExtract2PeersFromList()
   SharedHandle<ValueBase> dict = bencode2::decode(peersString);
 
   std::deque<SharedHandle<Peer> > peers;
-  extractPeer(asDict(dict)->get("peers"), std::back_inserter(peers));
+  extractPeer(asDict(dict)->get("peers"), AF_INET, std::back_inserter(peers));
   CPPUNIT_ASSERT_EQUAL((size_t)2, peers.size());
   SharedHandle<Peer> peer = *peers.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), peer->getIPAddress());
@@ -797,6 +818,40 @@ void BittorrentHelperTest::testExtract2PeersFromList()
   CPPUNIT_ASSERT_EQUAL((uint16_t)2007, peer->getPort());
 }
 
+void BittorrentHelperTest::testPackcompact()
+{
+  unsigned char compact[COMPACT_LEN_IPV6];
+  CPPUNIT_ASSERT_EQUAL(18,
+                       packcompact(compact,
+                                   "1002:1035:4527:3546:7854:1237:3247:3217",
+                                   6881));
+  CPPUNIT_ASSERT_EQUAL(std::string("100210354527354678541237324732171ae1"),
+                       util::toHex(compact, 18));
+
+  CPPUNIT_ASSERT_EQUAL(6, packcompact(compact, "192.168.0.1", 6881));
+  CPPUNIT_ASSERT_EQUAL(std::string("c0a800011ae1"), util::toHex(compact, 6));
+
+  CPPUNIT_ASSERT_EQUAL(0, packcompact(compact, "badaddr", 6881));
+}
+
+void BittorrentHelperTest::testUnpackcompact()
+{
+  unsigned char compact6[] = {
+    0x10, 0x02, 0x10, 0x35, 0x45, 0x27, 0x35, 0x46,
+    0x78, 0x54, 0x12, 0x37, 0x32, 0x47, 0x32, 0x17,
+    0x1A, 0xE1 };
+  std::pair<std::string, uint16_t> p =
+    unpackcompact(compact6, AF_INET6);
+  CPPUNIT_ASSERT_EQUAL(std::string("1002:1035:4527:3546:7854:1237:3247:3217"),
+                       p.first);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, p.second);
+
+  unsigned char compact[] = { 0xC0, 0xa8, 0x00, 0x01, 0x1A, 0xE1 };
+  p = unpackcompact(compact, AF_INET);
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), p.first);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, p.second);
+}
+
 } // namespace bittorrent
 
 } // namespace aria2

+ 4 - 4
test/DHTFindNodeReplyMessageTest.cc

@@ -45,12 +45,12 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
     nodes[i]->setIPAddress("192.168.0."+util::uitos(i+1));
     nodes[i]->setPort(6881+i);
 
-    unsigned char buf[6];
-    CPPUNIT_ASSERT(bittorrent::createcompact
-                   (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
+    unsigned char buf[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[sizeof(buf)]);
+      std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
   }
   msg.setClosestKNodes
     (std::vector<SharedHandle<DHTNode> >(&nodes[0], &nodes[DHTBucket::K]));

+ 7 - 8
test/DHTGetPeersReplyMessageTest.cc

@@ -57,12 +57,12 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage()
       nodes[i]->setIPAddress("192.168.0."+util::uitos(i+1));
       nodes[i]->setPort(6881+i);
       
-      unsigned char buf[6];
-      CPPUNIT_ASSERT(bittorrent::createcompact
-                     (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
+      unsigned char buf[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[sizeof(buf)]);
+        std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
     }
     msg.setClosestKNodes
       (std::vector<SharedHandle<DHTNode> >(&nodes[0], &nodes[DHTBucket::K]));
@@ -80,10 +80,9 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage()
     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[6];
-      CPPUNIT_ASSERT(bittorrent::createcompact
-                     (buffer, peer->getIPAddress(), peer->getPort()));
-      valuesList->append(String::g(buffer, sizeof(buffer)));
+      unsigned char buffer[COMPACT_LEN_IPV6];
+      bittorrent::packcompact(buffer, peer->getIPAddress(), peer->getPort());
+      valuesList->append(String::g(buffer, COMPACT_LEN_IPV4));
       peers.push_back(peer);
     }
     rDict->put("values", valuesList);

+ 12 - 12
test/DHTMessageFactoryImplTest.cc

@@ -168,12 +168,12 @@ void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage()
       nodes[i]->setIPAddress("192.168.0."+util::uitos(i+1));
       nodes[i]->setPort(6881+i);
 
-      unsigned char buf[6];
-      CPPUNIT_ASSERT(bittorrent::createcompact
-                     (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
+      unsigned char buf[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[sizeof(buf)]);
+        std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
     }
     rDict->put("nodes", compactNodeInfo);
     dict.put("r", rDict);
@@ -243,12 +243,12 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes()
       nodes[i]->setIPAddress("192.168.0."+util::uitos(i+1));
       nodes[i]->setPort(6881+i);
 
-      unsigned char buf[6];
-      CPPUNIT_ASSERT(bittorrent::createcompact
-                     (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
+      unsigned char buf[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[sizeof(buf)]);
+        std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
     }
     rDict->put("nodes", compactNodeInfo);
     rDict->put("token", "token");
@@ -290,10 +290,10 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_values()
     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[6];
-      CPPUNIT_ASSERT(bittorrent::createcompact
-                     (buffer, peer->getIPAddress(), peer->getPort()));
-      valuesList->append(String::g(buffer, sizeof(buffer)));
+      unsigned char buffer[COMPACT_LEN_IPV6];
+      bittorrent::packcompact
+        (buffer, peer->getIPAddress(), peer->getPort());
+      valuesList->append(String::g(buffer, COMPACT_LEN_IPV4));
       peers.push_back(peer);
     }
     rDict->put("values", valuesList);

+ 4 - 2
test/DHTRoutingTableSerializerTest.cc

@@ -115,7 +115,8 @@ void DHTRoutingTableSerializerTest::testSerialize()
   ss.read(buf, 6);
   {
     std::pair<std::string, uint16_t> peer =
-      bittorrent::unpackcompact(reinterpret_cast<const unsigned char*>(buf));
+      bittorrent::unpackcompact(reinterpret_cast<const unsigned char*>(buf),
+                                AF_INET);
     CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), peer.first);
     CPPUNIT_ASSERT_EQUAL((uint16_t)6881, peer.second);
   }
@@ -174,7 +175,8 @@ void DHTRoutingTableSerializerTest::testSerialize()
   ss.read(buf, 6);
   {
     std::pair<std::string, uint16_t> peer =
-      bittorrent::unpackcompact(reinterpret_cast<const unsigned char*>(buf));
+      bittorrent::unpackcompact(reinterpret_cast<const unsigned char*>(buf),
+                                AF_INET);
     CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.3"), peer.first);
     CPPUNIT_ASSERT_EQUAL((uint16_t)6883, peer.second);
   }

+ 8 - 8
test/DefaultExtensionMessageFactoryTest.cc

@@ -131,14 +131,14 @@ void DefaultExtensionMessageFactoryTest::testCreateMessage_Handshake()
 
 void DefaultExtensionMessageFactoryTest::testCreateMessage_UTPex()
 {
-  unsigned char c1[6];
-  unsigned char c2[6];
-  unsigned char c3[6];
-  unsigned char c4[6];
-  bittorrent::createcompact(c1, "192.168.0.1", 6881);
-  bittorrent::createcompact(c2, "10.1.1.2", 9999);
-  bittorrent::createcompact(c3, "192.168.0.2", 6882);
-  bittorrent::createcompact(c4, "10.1.1.3",10000);
+  unsigned char c1[COMPACT_LEN_IPV6];
+  unsigned char c2[COMPACT_LEN_IPV6];
+  unsigned char c3[COMPACT_LEN_IPV6];
+  unsigned char c4[COMPACT_LEN_IPV6];
+  bittorrent::packcompact(c1, "192.168.0.1", 6881);
+  bittorrent::packcompact(c2, "10.1.1.2", 9999);
+  bittorrent::packcompact(c3, "192.168.0.2", 6882);
+  bittorrent::packcompact(c4, "10.1.1.3",10000);
 
   std::string data = getExtensionMessageID("ut_pex")+"d5:added12:"+
     std::string(&c1[0], &c1[6])+std::string(&c2[0], &c2[6])+

+ 17 - 17
test/UTPexExtensionMessageTest.cc

@@ -81,18 +81,18 @@ void UTPexExtensionMessageTest::testGetBencodedData()
   p4->startBadCondition();
   CPPUNIT_ASSERT(msg.addDroppedPeer(p4));
 
-  unsigned char c1[6];
-  unsigned char c2[6];
-  unsigned char c3[6];
-  unsigned char c4[6];
-  bittorrent::createcompact(c1, p1->getIPAddress(), p1->getPort());
-  bittorrent::createcompact(c2, p2->getIPAddress(), p2->getPort());
-  bittorrent::createcompact(c3, p3->getIPAddress(), p3->getPort());
-  bittorrent::createcompact(c4, p4->getIPAddress(), p4->getPort());
+  unsigned char c1[COMPACT_LEN_IPV6];
+  unsigned char c2[COMPACT_LEN_IPV6];
+  unsigned char c3[COMPACT_LEN_IPV6];
+  unsigned char c4[COMPACT_LEN_IPV6];
+  bittorrent::packcompact(c1, p1->getIPAddress(), p1->getPort());
+  bittorrent::packcompact(c2, p2->getIPAddress(), p2->getPort());
+  bittorrent::packcompact(c3, p3->getIPAddress(), p3->getPort());
+  bittorrent::packcompact(c4, p4->getIPAddress(), p4->getPort());
 
   std::string expected = "d5:added12:"+
     std::string(&c1[0], &c1[6])+std::string(&c2[0], &c2[6])+
-    "7:added.f2:207:dropped12:"+
+    "7:added.f2:"+util::fromHex("0200")+"7:dropped12:"+
     std::string(&c3[0], &c3[6])+std::string(&c4[0], &c4[6])+
     "e";
   std::string bd = msg.getPayload();
@@ -152,14 +152,14 @@ void UTPexExtensionMessageTest::testDoReceivedAction()
 
 void UTPexExtensionMessageTest::testCreate()
 {
-  unsigned char c1[6];
-  unsigned char c2[6];
-  unsigned char c3[6];
-  unsigned char c4[6];
-  bittorrent::createcompact(c1, "192.168.0.1", 6881);
-  bittorrent::createcompact(c2, "10.1.1.2", 9999);
-  bittorrent::createcompact(c3, "192.168.0.2", 6882);
-  bittorrent::createcompact(c4, "10.1.1.3",10000);
+  unsigned char c1[COMPACT_LEN_IPV6];
+  unsigned char c2[COMPACT_LEN_IPV6];
+  unsigned char c3[COMPACT_LEN_IPV6];
+  unsigned char c4[COMPACT_LEN_IPV6];
+  bittorrent::packcompact(c1, "192.168.0.1", 6881);
+  bittorrent::packcompact(c2, "10.1.1.2", 9999);
+  bittorrent::packcompact(c3, "192.168.0.2", 6882);
+  bittorrent::packcompact(c4, "10.1.1.3",10000);
 
   char id[1] = { 1 };