DHTBucketTest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #include "DHTBucket.h"
  2. #include "DHTNode.h"
  3. #include "Exception.h"
  4. #include "Util.h"
  5. #include <cstring>
  6. #include <algorithm>
  7. #include <cppunit/extensions/HelperMacros.h>
  8. namespace aria2 {
  9. class DHTBucketTest:public CppUnit::TestFixture {
  10. CPPUNIT_TEST_SUITE(DHTBucketTest);
  11. CPPUNIT_TEST(testGetRandomNodeID);
  12. CPPUNIT_TEST(testIsInRange);
  13. CPPUNIT_TEST(testSplitAllowed);
  14. CPPUNIT_TEST(testSplit);
  15. CPPUNIT_TEST(testAddNode);
  16. CPPUNIT_TEST(testMoveToHead);
  17. CPPUNIT_TEST(testMoveToTail);
  18. CPPUNIT_TEST(testGetGoodNodes);
  19. CPPUNIT_TEST_SUITE_END();
  20. public:
  21. void setUp() {}
  22. void tearDown() {}
  23. void testGetRandomNodeID();
  24. void testIsInRange();
  25. void testSplitAllowed();
  26. void testSplit();
  27. void testAddNode();
  28. void testMoveToHead();
  29. void testMoveToTail();
  30. void testGetGoodNodes();
  31. };
  32. CPPUNIT_TEST_SUITE_REGISTRATION(DHTBucketTest);
  33. void DHTBucketTest::testGetRandomNodeID()
  34. {
  35. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  36. 0x00, 0x00, 0x00, 0x00, 0x00,
  37. 0x00, 0x00, 0x00, 0x00, 0x00,
  38. 0x00, 0x00, 0x00, 0x00, 0x00 };
  39. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  40. {
  41. DHTBucket bucket(localNode);
  42. unsigned char nodeID[DHT_ID_LENGTH];
  43. bucket.getRandomNodeID(nodeID);
  44. }
  45. {
  46. unsigned char max[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  47. 0xff, 0xff, 0xff, 0xff, 0xff,
  48. 0xff, 0xff, 0xff, 0xff, 0xff,
  49. 0xff, 0xff, 0xff, 0xff, 0xff };
  50. unsigned char min[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  51. 0x00, 0x00, 0x00, 0x00, 0x00,
  52. 0x00, 0x00, 0x00, 0x00, 0x00,
  53. 0x00, 0x00, 0x00, 0x00, 0x00 };
  54. DHTBucket bucket(16, max, min, localNode);
  55. unsigned char nodeID[DHT_ID_LENGTH];
  56. bucket.getRandomNodeID(nodeID);
  57. CPPUNIT_ASSERT_EQUAL(std::string("0101"),
  58. Util::toHex(nodeID, sizeof(nodeID)).substr(0, 4));
  59. }
  60. }
  61. void DHTBucketTest::testIsInRange()
  62. {
  63. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  64. 0x00, 0x00, 0x00, 0x00, 0x00,
  65. 0x00, 0x00, 0x00, 0x00, 0x00,
  66. 0x00, 0x00, 0x00, 0x00, 0x00 };
  67. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  68. {
  69. unsigned char nodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  70. 0x00, 0x00, 0x00, 0x00, 0x00,
  71. 0x00, 0x00, 0x00, 0x00, 0x00,
  72. 0x00, 0x00, 0x00, 0x00, 0x00 };
  73. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  74. DHTBucket bucket(localNode);
  75. CPPUNIT_ASSERT(bucket.isInRange(node));
  76. memset(nodeID, 0xff, sizeof(nodeID));
  77. CPPUNIT_ASSERT(bucket.isInRange(node));
  78. }
  79. {
  80. unsigned char max[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  81. 0xff, 0xff, 0xff, 0xff, 0xff,
  82. 0xff, 0xff, 0xff, 0xff, 0xff,
  83. 0xff, 0xff, 0xff, 0xff, 0xff };
  84. unsigned char min[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  85. 0x00, 0x00, 0x00, 0x00, 0x00,
  86. 0x00, 0x00, 0x00, 0x00, 0x00,
  87. 0x00, 0x00, 0x00, 0x00, 0x00 };
  88. {
  89. //min
  90. unsigned char nodeID[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  91. 0x00, 0x00, 0x00, 0x00, 0x00,
  92. 0x00, 0x00, 0x00, 0x00, 0x00,
  93. 0x00, 0x00, 0x00, 0x00, 0x00 };
  94. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  95. DHTBucket bucket(16, max, min, localNode);
  96. CPPUNIT_ASSERT(bucket.isInRange(node));
  97. }
  98. {
  99. //max
  100. unsigned char nodeID[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  101. 0xff, 0xff, 0xff, 0xff, 0xff,
  102. 0xff, 0xff, 0xff, 0xff, 0xff,
  103. 0xff, 0xff, 0xff, 0xff, 0xff };
  104. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  105. DHTBucket bucket(16, max, min, localNode);
  106. CPPUNIT_ASSERT(bucket.isInRange(node));
  107. }
  108. {
  109. unsigned char nodeID[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  110. 0x00, 0x00, 0x00, 0x00, 0x00,
  111. 0xff, 0xff, 0xff, 0xff, 0xff,
  112. 0xff, 0xff, 0xff, 0xff, 0xff };
  113. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  114. DHTBucket bucket(16, max, min, localNode);
  115. CPPUNIT_ASSERT(bucket.isInRange(node));
  116. }
  117. {
  118. // nodeID is out of range: smaller than this range
  119. unsigned char nodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  120. 0x00, 0x00, 0x00, 0x00, 0x00,
  121. 0x00, 0x00, 0x00, 0x00, 0x00,
  122. 0x00, 0x00, 0x00, 0x00, 0x00 };
  123. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  124. DHTBucket bucket(16, max, min, localNode);
  125. CPPUNIT_ASSERT(!bucket.isInRange(node));
  126. }
  127. {
  128. // nodeID is out of range: larger than this range
  129. unsigned char nodeID[] = { 0x10, 0x00, 0x00, 0x00, 0x00,
  130. 0x00, 0x00, 0x00, 0x00, 0x00,
  131. 0x00, 0x00, 0x00, 0x00, 0x00,
  132. 0x00, 0x00, 0x00, 0x00, 0x00 };
  133. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  134. DHTBucket bucket(16, max, min, localNode);
  135. CPPUNIT_ASSERT(!bucket.isInRange(node));
  136. }
  137. }
  138. }
  139. void DHTBucketTest::testSplitAllowed()
  140. {
  141. {
  142. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  143. 0x00, 0x00, 0x00, 0x00, 0x00,
  144. 0x00, 0x00, 0x00, 0x00, 0x00,
  145. 0x00, 0x00, 0x00, 0x00, 0x00 };
  146. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  147. DHTBucket bucket(localNode);
  148. CPPUNIT_ASSERT(bucket.splitAllowed());
  149. }
  150. {
  151. unsigned char max[] = { 0xff, 0xff, 0xff, 0xff, 0xff,
  152. 0xff, 0xff, 0xff, 0xff, 0xff,
  153. 0xff, 0xff, 0xff, 0xff, 0xff,
  154. 0xff, 0xff, 0xff, 0xff, 0xff };
  155. unsigned char min[] = { 0xe0, 0x00, 0x00, 0x00, 0x00,
  156. 0x00, 0x00, 0x00, 0x00, 0x00,
  157. 0x00, 0x00, 0x00, 0x00, 0x00,
  158. 0x00, 0x00, 0x00, 0x00, 0x00 };
  159. {
  160. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  161. 0x00, 0x00, 0x00, 0x00, 0x00,
  162. 0x00, 0x00, 0x00, 0x00, 0x00,
  163. 0x00, 0x00, 0x00, 0x00, 0x00 };
  164. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  165. DHTBucket bucket(3, max, min, localNode);
  166. CPPUNIT_ASSERT(!bucket.splitAllowed());
  167. }
  168. {
  169. unsigned char localNodeID[] = { 0xe0, 0x00, 0x00, 0x00, 0x00,
  170. 0x00, 0x00, 0x00, 0x00, 0x00,
  171. 0x00, 0x00, 0x00, 0x00, 0x00,
  172. 0x00, 0x00, 0x00, 0x00, 0x01 };
  173. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  174. DHTBucket bucket(3, max, min, localNode);
  175. CPPUNIT_ASSERT(bucket.splitAllowed());
  176. }
  177. }
  178. }
  179. void DHTBucketTest::testSplit()
  180. {
  181. unsigned char localNodeID[DHT_ID_LENGTH];
  182. memset(localNodeID, 0, DHT_ID_LENGTH);
  183. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  184. {
  185. DHTBucket bucket(localNode);
  186. SharedHandle<DHTBucket> r = bucket.split();
  187. {
  188. unsigned char expectedRMax[] = { 0x7f, 0xff, 0xff, 0xff, 0xff,
  189. 0xff, 0xff, 0xff, 0xff, 0xff,
  190. 0xff, 0xff, 0xff, 0xff, 0xff,
  191. 0xff, 0xff, 0xff, 0xff, 0xff };
  192. unsigned char expectedRMin[DHT_ID_LENGTH];
  193. memset(expectedRMin, 0, DHT_ID_LENGTH);
  194. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedRMax, DHT_ID_LENGTH),
  195. Util::toHex(r->getMaxID(), DHT_ID_LENGTH));
  196. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedRMin, DHT_ID_LENGTH),
  197. Util::toHex(r->getMinID(), DHT_ID_LENGTH));
  198. CPPUNIT_ASSERT_EQUAL((size_t)1, r->getPrefixLength());
  199. }
  200. {
  201. unsigned char expectedLMax[DHT_ID_LENGTH];
  202. memset(expectedLMax, 0xff, DHT_ID_LENGTH);
  203. unsigned char expectedLMin[] = { 0x80, 0x00, 0x00, 0x00, 0x00,
  204. 0x00, 0x00, 0x00, 0x00, 0x00,
  205. 0x00, 0x00, 0x00, 0x00, 0x00,
  206. 0x00, 0x00, 0x00, 0x00, 0x00 };
  207. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedLMax, DHT_ID_LENGTH),
  208. Util::toHex(bucket.getMaxID(), DHT_ID_LENGTH));
  209. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedLMin, DHT_ID_LENGTH),
  210. Util::toHex(bucket.getMinID(), DHT_ID_LENGTH));
  211. CPPUNIT_ASSERT_EQUAL((size_t)1, bucket.getPrefixLength());
  212. }
  213. }
  214. {
  215. SharedHandle<DHTBucket> bucket = new DHTBucket(localNode);
  216. for(int i = 0; i < 159; ++i) {
  217. CPPUNIT_ASSERT(bucket->splitAllowed());
  218. SharedHandle<DHTBucket> t = bucket;
  219. bucket = bucket->split();
  220. CPPUNIT_ASSERT(!t->splitAllowed());
  221. }
  222. CPPUNIT_ASSERT(!bucket->splitAllowed());
  223. unsigned char expectedMax[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  224. 0x00, 0x00, 0x00, 0x00, 0x00,
  225. 0x00, 0x00, 0x00, 0x00, 0x00,
  226. 0x00, 0x00, 0x00, 0x00, 0x01 };
  227. unsigned char expectedMin[DHT_ID_LENGTH];
  228. memset(expectedMin, 0, DHT_ID_LENGTH);
  229. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedMax, DHT_ID_LENGTH),
  230. Util::toHex(bucket->getMaxID(), DHT_ID_LENGTH));
  231. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedMin, DHT_ID_LENGTH),
  232. Util::toHex(bucket->getMinID(), DHT_ID_LENGTH));
  233. CPPUNIT_ASSERT_EQUAL((size_t)159, bucket->getPrefixLength());
  234. }
  235. }
  236. static void createID(unsigned char* id, unsigned char firstChar, unsigned char lastChar)
  237. {
  238. memset(id, 0, DHT_ID_LENGTH);
  239. id[0] = firstChar;
  240. id[DHT_ID_LENGTH-1] = lastChar;
  241. }
  242. void DHTBucketTest::testAddNode()
  243. {
  244. unsigned char localNodeID[DHT_ID_LENGTH];
  245. memset(localNodeID, 0, DHT_ID_LENGTH);
  246. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  247. DHTBucket bucket(localNode);
  248. unsigned char id[DHT_ID_LENGTH];
  249. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  250. for(size_t i = 0; i < DHTBucket::K; ++i) {
  251. createID(id, 0xf0, i);
  252. nodes[i] = new DHTNode(id);
  253. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  254. }
  255. createID(id, 0xf0, 0xff);
  256. SharedHandle<DHTNode> newNode = new DHTNode(id);
  257. CPPUNIT_ASSERT(!bucket.addNode(newNode));
  258. // nodes[0] is located at the tail of the bucket(least recent seen)
  259. nodes[0]->markBad();
  260. CPPUNIT_ASSERT(bucket.addNode(newNode));
  261. CPPUNIT_ASSERT(bucket.getNodes().back() == newNode);
  262. }
  263. void DHTBucketTest::testMoveToHead()
  264. {
  265. unsigned char localNodeID[DHT_ID_LENGTH];
  266. memset(localNodeID, 0, DHT_ID_LENGTH);
  267. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  268. DHTBucket bucket(localNode);
  269. unsigned char id[DHT_ID_LENGTH];
  270. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  271. for(size_t i = 0; i < DHTBucket::K; ++i) {
  272. createID(id, 0xf0, i);
  273. nodes[i] = new DHTNode(id);
  274. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  275. }
  276. bucket.moveToHead(nodes[DHTBucket::K-1]);
  277. CPPUNIT_ASSERT(bucket.getNodes().front() == nodes[DHTBucket::K-1]);
  278. }
  279. void DHTBucketTest::testMoveToTail()
  280. {
  281. unsigned char localNodeID[DHT_ID_LENGTH];
  282. memset(localNodeID, 0, DHT_ID_LENGTH);
  283. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  284. DHTBucket bucket(localNode);
  285. unsigned char id[DHT_ID_LENGTH];
  286. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  287. for(size_t i = 0; i < DHTBucket::K; ++i) {
  288. createID(id, 0xf0, i);
  289. nodes[i] = new DHTNode(id);
  290. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  291. }
  292. bucket.moveToTail(nodes[0]);
  293. CPPUNIT_ASSERT(bucket.getNodes().back() == nodes[0]);
  294. }
  295. void DHTBucketTest::testGetGoodNodes()
  296. {
  297. unsigned char localNodeID[DHT_ID_LENGTH];
  298. memset(localNodeID, 0, DHT_ID_LENGTH);
  299. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  300. DHTBucket bucket(localNode);
  301. unsigned char id[DHT_ID_LENGTH];
  302. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  303. for(size_t i = 0; i < DHTBucket::K; ++i) {
  304. createID(id, 0xf0, i);
  305. nodes[i] = new DHTNode(id);
  306. nodes[i]->setPort(6881+i);
  307. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  308. }
  309. nodes[3]->markBad();
  310. nodes[5]->markBad();
  311. std::deque<SharedHandle<DHTNode> > goodNodes = bucket.getGoodNodes();
  312. CPPUNIT_ASSERT_EQUAL((size_t)6, goodNodes.size());
  313. CPPUNIT_ASSERT_EQUAL((uint16_t)6881, goodNodes[0]->getPort());
  314. CPPUNIT_ASSERT_EQUAL((uint16_t)6882, goodNodes[1]->getPort());
  315. CPPUNIT_ASSERT_EQUAL((uint16_t)6883, goodNodes[2]->getPort());
  316. CPPUNIT_ASSERT_EQUAL((uint16_t)6885, goodNodes[3]->getPort());
  317. CPPUNIT_ASSERT_EQUAL((uint16_t)6887, goodNodes[4]->getPort());
  318. CPPUNIT_ASSERT_EQUAL((uint16_t)6888, goodNodes[5]->getPort());
  319. }
  320. } // namespace aria2