| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 | #include "DHTBucket.h"#include <cstring>#include <algorithm>#include <cppunit/extensions/HelperMacros.h>#include "DHTNode.h"#include "Exception.h"#include "util.h"namespace aria2 {class DHTBucketTest : public CppUnit::TestFixture {  CPPUNIT_TEST_SUITE(DHTBucketTest);  CPPUNIT_TEST(testGetRandomNodeID);  CPPUNIT_TEST(testIsInRange);  CPPUNIT_TEST(testSplitAllowed);  CPPUNIT_TEST(testSplit);  CPPUNIT_TEST(testAddNode);  CPPUNIT_TEST(testMoveToHead);  CPPUNIT_TEST(testMoveToTail);  CPPUNIT_TEST(testGetGoodNodes);  CPPUNIT_TEST(testCacheNode);  CPPUNIT_TEST(testDropNode);  CPPUNIT_TEST(testGetNode);  CPPUNIT_TEST_SUITE_END();public:  void setUp() {}  void tearDown() {}  void testGetRandomNodeID();  void testIsInRange();  void testSplitAllowed();  void testSplit();  void testAddNode();  void testMoveToHead();  void testMoveToTail();  void testGetGoodNodes();  void testCacheNode();  void testDropNode();  void testGetNode();};CPPUNIT_TEST_SUITE_REGISTRATION(DHTBucketTest);void DHTBucketTest::testGetRandomNodeID(){  unsigned char localNodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  {    DHTBucket bucket(localNode);    unsigned char nodeID[DHT_ID_LENGTH];    bucket.getRandomNodeID(nodeID);  }  {    unsigned char max[] = {0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff};    unsigned char min[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    DHTBucket bucket(16, max, min, localNode);    unsigned char nodeID[DHT_ID_LENGTH];    bucket.getRandomNodeID(nodeID);    CPPUNIT_ASSERT_EQUAL(std::string("0101"),                         util::toHex(nodeID, sizeof(nodeID)).substr(0, 4));  }}void DHTBucketTest::testIsInRange(){  unsigned char localNodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  {    unsigned char nodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    std::shared_ptr<DHTNode> node(new DHTNode(nodeID));    DHTBucket bucket(localNode);    CPPUNIT_ASSERT(bucket.isInRange(node));    memset(nodeID, 0xff, sizeof(nodeID));    CPPUNIT_ASSERT(bucket.isInRange(node));  }  {    unsigned char max[] = {0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff};    unsigned char min[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    {      // min      unsigned char nodeID[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00};      std::shared_ptr<DHTNode> node(new DHTNode(nodeID));      DHTBucket bucket(16, max, min, localNode);      CPPUNIT_ASSERT(bucket.isInRange(node));    }    {      // max      unsigned char nodeID[] = {0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff};      std::shared_ptr<DHTNode> node(new DHTNode(nodeID));      DHTBucket bucket(16, max, min, localNode);      CPPUNIT_ASSERT(bucket.isInRange(node));    }    {      unsigned char nodeID[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,                                0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff};      std::shared_ptr<DHTNode> node(new DHTNode(nodeID));      DHTBucket bucket(16, max, min, localNode);      CPPUNIT_ASSERT(bucket.isInRange(node));    }    {      // nodeID is out of range: smaller than this range      unsigned char nodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00};      std::shared_ptr<DHTNode> node(new DHTNode(nodeID));      DHTBucket bucket(16, max, min, localNode);      CPPUNIT_ASSERT(!bucket.isInRange(node));    }    {      // nodeID is out of range: larger than this range      unsigned char nodeID[] = {0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff,                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff};      std::shared_ptr<DHTNode> node(new DHTNode(nodeID));      DHTBucket bucket(16, max, min, localNode);      CPPUNIT_ASSERT(!bucket.isInRange(node));    }  }}void DHTBucketTest::testSplitAllowed(){  {    unsigned char localNodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));    DHTBucket bucket(localNode);    CPPUNIT_ASSERT(bucket.splitAllowed());  }  {    unsigned char max[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                           0xff, 0xff, 0xff, 0xff, 0xff, 0xff};    unsigned char min[] = {0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    {      unsigned char localNodeID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00};      std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));      DHTBucket bucket(3, max, min, localNode);      CPPUNIT_ASSERT(!bucket.splitAllowed());    }    {      unsigned char localNodeID[] = {0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x01};      std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));      DHTBucket bucket(3, max, min, localNode);      CPPUNIT_ASSERT(bucket.splitAllowed());    }  }}void DHTBucketTest::testSplit(){  {    unsigned char localNodeID[DHT_ID_LENGTH];    memset(localNodeID, 0, DHT_ID_LENGTH);    std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));    {      DHTBucket bucket(localNode);      std::shared_ptr<DHTBucket> r = bucket.split();      {        unsigned char expectedRMax[] = {            0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};        unsigned char expectedRMin[DHT_ID_LENGTH];        memset(expectedRMin, 0, DHT_ID_LENGTH);        CPPUNIT_ASSERT_EQUAL(util::toHex(expectedRMax, DHT_ID_LENGTH),                             util::toHex(r->getMaxID(), DHT_ID_LENGTH));        CPPUNIT_ASSERT_EQUAL(util::toHex(expectedRMin, DHT_ID_LENGTH),                             util::toHex(r->getMinID(), DHT_ID_LENGTH));        CPPUNIT_ASSERT_EQUAL((size_t)1, r->getPrefixLength());      }      {        unsigned char expectedLMax[DHT_ID_LENGTH];        memset(expectedLMax, 0xff, DHT_ID_LENGTH);        unsigned char expectedLMin[] = {            0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};        CPPUNIT_ASSERT_EQUAL(util::toHex(expectedLMax, DHT_ID_LENGTH),                             util::toHex(bucket.getMaxID(), DHT_ID_LENGTH));        CPPUNIT_ASSERT_EQUAL(util::toHex(expectedLMin, DHT_ID_LENGTH),                             util::toHex(bucket.getMinID(), DHT_ID_LENGTH));        CPPUNIT_ASSERT_EQUAL((size_t)1, bucket.getPrefixLength());      }    }    {      std::shared_ptr<DHTBucket> bucket(new DHTBucket(localNode));      for (int i = 0; i < 159; ++i) {        CPPUNIT_ASSERT(bucket->splitAllowed());        std::shared_ptr<DHTBucket> t = bucket;        bucket = bucket->split();        CPPUNIT_ASSERT(!t->splitAllowed());      }      CPPUNIT_ASSERT(!bucket->splitAllowed());      unsigned char expectedMax[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x01};      unsigned char expectedMin[DHT_ID_LENGTH];      memset(expectedMin, 0, DHT_ID_LENGTH);      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedMax, DHT_ID_LENGTH),                           util::toHex(bucket->getMaxID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedMin, DHT_ID_LENGTH),                           util::toHex(bucket->getMinID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL((size_t)159, bucket->getPrefixLength());    }  }  {    unsigned char localNodeID[DHT_ID_LENGTH];    memset(localNodeID, 0, DHT_ID_LENGTH);    localNodeID[0] = 0x80;    std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));    DHTBucket bucket(localNode);    std::shared_ptr<DHTBucket> r = bucket.split();    {      unsigned char expectedRMax[] = {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                                      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,                                      0xff, 0xff, 0xff, 0xff, 0xff, 0xff};      unsigned char expectedRMin[DHT_ID_LENGTH];      memset(expectedRMin, 0, DHT_ID_LENGTH);      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedRMax, DHT_ID_LENGTH),                           util::toHex(r->getMaxID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedRMin, DHT_ID_LENGTH),                           util::toHex(r->getMinID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL((size_t)1, r->getPrefixLength());    }    {      unsigned char expectedLMax[DHT_ID_LENGTH];      memset(expectedLMax, 0xff, DHT_ID_LENGTH);      unsigned char expectedLMin[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00};      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedLMax, DHT_ID_LENGTH),                           util::toHex(bucket.getMaxID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL(util::toHex(expectedLMin, DHT_ID_LENGTH),                           util::toHex(bucket.getMinID(), DHT_ID_LENGTH));      CPPUNIT_ASSERT_EQUAL((size_t)1, bucket.getPrefixLength());    }  }}namespace {void createID(unsigned char* id, unsigned char firstChar,              unsigned char lastChar){  memset(id, 0, DHT_ID_LENGTH);  id[0] = firstChar;  id[DHT_ID_LENGTH - 1] = lastChar;}} // namespacevoid DHTBucketTest::testAddNode(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  std::shared_ptr<DHTNode> nodes[8];  for (size_t i = 0; i < DHTBucket::K; ++i) {    createID(id, 0xf0, i);    nodes[i].reset(new DHTNode(id));    CPPUNIT_ASSERT(bucket.addNode(nodes[i]));  }  createID(id, 0xf0, 0xff);  std::shared_ptr<DHTNode> newNode(new DHTNode(id));  CPPUNIT_ASSERT(!bucket.addNode(newNode));  // nodes[0] is located at the tail of the bucket(least recent seen)  nodes[0]->markBad();  CPPUNIT_ASSERT(bucket.addNode(newNode));  CPPUNIT_ASSERT(*bucket.getNodes().back() == *newNode);}void DHTBucketTest::testMoveToHead(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  std::shared_ptr<DHTNode> nodes[8];  for (size_t i = 0; i < DHTBucket::K; ++i) {    createID(id, 0xf0, i);    nodes[i].reset(new DHTNode(id));    CPPUNIT_ASSERT(bucket.addNode(nodes[i]));  }  bucket.moveToHead(nodes[DHTBucket::K - 1]);  CPPUNIT_ASSERT(*bucket.getNodes().front() == *nodes[DHTBucket::K - 1]);}void DHTBucketTest::testMoveToTail(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  std::shared_ptr<DHTNode> nodes[8];  for (size_t i = 0; i < DHTBucket::K; ++i) {    createID(id, 0xf0, i);    nodes[i].reset(new DHTNode(id));    CPPUNIT_ASSERT(bucket.addNode(nodes[i]));  }  bucket.moveToTail(nodes[0]);  CPPUNIT_ASSERT(*bucket.getNodes().back() == *nodes[0]);}void DHTBucketTest::testGetGoodNodes(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  std::shared_ptr<DHTNode> nodes[8];  for (size_t i = 0; i < DHTBucket::K; ++i) {    createID(id, 0xf0, i);    nodes[i].reset(new DHTNode(id));    nodes[i]->setPort(6881 + i);    CPPUNIT_ASSERT(bucket.addNode(nodes[i]));  }  nodes[3]->markBad();  nodes[5]->markBad();  std::vector<std::shared_ptr<DHTNode>> goodNodes;  bucket.getGoodNodes(goodNodes);  CPPUNIT_ASSERT_EQUAL((size_t)6, goodNodes.size());  CPPUNIT_ASSERT_EQUAL((uint16_t)6881, goodNodes[0]->getPort());  CPPUNIT_ASSERT_EQUAL((uint16_t)6882, goodNodes[1]->getPort());  CPPUNIT_ASSERT_EQUAL((uint16_t)6883, goodNodes[2]->getPort());  CPPUNIT_ASSERT_EQUAL((uint16_t)6885, goodNodes[3]->getPort());  CPPUNIT_ASSERT_EQUAL((uint16_t)6887, goodNodes[4]->getPort());  CPPUNIT_ASSERT_EQUAL((uint16_t)6888, goodNodes[5]->getPort());}void DHTBucketTest::testCacheNode(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  std::shared_ptr<DHTNode> n1(new DHTNode());  std::shared_ptr<DHTNode> n2(new DHTNode());  std::shared_ptr<DHTNode> n3(new DHTNode());  bucket.cacheNode(n1);  bucket.cacheNode(n2);  CPPUNIT_ASSERT_EQUAL((size_t)2, bucket.getCachedNodes().size());  CPPUNIT_ASSERT(*n2 == *bucket.getCachedNodes()[0]);  bucket.cacheNode(n3);  CPPUNIT_ASSERT_EQUAL((size_t)2, bucket.getCachedNodes().size());  CPPUNIT_ASSERT(*n3 == *bucket.getCachedNodes()[0]);  CPPUNIT_ASSERT(*n2 == *bucket.getCachedNodes()[1]);}void DHTBucketTest::testDropNode(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  std::shared_ptr<DHTNode> nodes[8];  for (size_t i = 0; i < DHTBucket::K; ++i) {    createID(id, 0xf0, i);    nodes[i].reset(new DHTNode(id));    nodes[i]->setPort(6881 + i);    CPPUNIT_ASSERT(bucket.addNode(nodes[i]));  }  std::shared_ptr<DHTNode> cachedNode1(new DHTNode());  std::shared_ptr<DHTNode> cachedNode2(new DHTNode());  bucket.dropNode(nodes[3]);  // nothing happens because the replacement cache is empty.  {    std::deque<std::shared_ptr<DHTNode>> tnodes = bucket.getNodes();    CPPUNIT_ASSERT_EQUAL((size_t)8, tnodes.size());    CPPUNIT_ASSERT(*nodes[3] == *tnodes[3]);  }  bucket.cacheNode(cachedNode1);  bucket.cacheNode(cachedNode2);  bucket.dropNode(nodes[3]);  {    std::deque<std::shared_ptr<DHTNode>> tnodes = bucket.getNodes();    CPPUNIT_ASSERT_EQUAL((size_t)8, tnodes.size());    CPPUNIT_ASSERT(tnodes.end() == std::find_if(tnodes.begin(), tnodes.end(),                                                derefEqual(nodes[3])));    CPPUNIT_ASSERT(*cachedNode2 == *tnodes[7]);  }  CPPUNIT_ASSERT_EQUAL((size_t)1, bucket.getCachedNodes().size());  CPPUNIT_ASSERT(*cachedNode1 == *bucket.getCachedNodes()[0]);}void DHTBucketTest::testGetNode(){  unsigned char localNodeID[DHT_ID_LENGTH];  memset(localNodeID, 0, DHT_ID_LENGTH);  std::shared_ptr<DHTNode> localNode(new DHTNode(localNodeID));  DHTBucket bucket(localNode);  unsigned char id[DHT_ID_LENGTH];  createID(id, 0xf0, 0);  std::shared_ptr<DHTNode> node(new DHTNode(id));  node->setIPAddress("192.168.0.1");  node->setPort(6881);  CPPUNIT_ASSERT(bucket.addNode(node));  CPPUNIT_ASSERT(bucket.getNode(id, "192.168.0.1", 6881));  CPPUNIT_ASSERT(!bucket.getNode(id, "192.168.0.2", 6881));  CPPUNIT_ASSERT(!bucket.getNode(id, "192.168.0.1", 6882));  CPPUNIT_ASSERT(!bucket.getNode(localNodeID, "192.168.0.1", 6881));}} // namespace aria2
 |