UDPTrackerClientTest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. #include "UDPTrackerClient.h"
  2. #include <cstring>
  3. #include <cppunit/extensions/HelperMacros.h>
  4. #include "TestUtil.h"
  5. #include "UDPTrackerRequest.h"
  6. #include "bittorrent_helper.h"
  7. #include "wallclock.h"
  8. namespace aria2 {
  9. class UDPTrackerClientTest : public CppUnit::TestFixture {
  10. CPPUNIT_TEST_SUITE(UDPTrackerClientTest);
  11. CPPUNIT_TEST(testCreateUDPTrackerConnect);
  12. CPPUNIT_TEST(testCreateUDPTrackerAnnounce);
  13. CPPUNIT_TEST(testConnectFollowedByAnnounce);
  14. CPPUNIT_TEST(testRequestFailure);
  15. CPPUNIT_TEST(testTimeout);
  16. CPPUNIT_TEST_SUITE_END();
  17. public:
  18. void setUp() {}
  19. void testCreateUDPTrackerConnect();
  20. void testCreateUDPTrackerAnnounce();
  21. void testConnectFollowedByAnnounce();
  22. void testRequestFailure();
  23. void testTimeout();
  24. };
  25. CPPUNIT_TEST_SUITE_REGISTRATION(UDPTrackerClientTest);
  26. namespace {
  27. std::shared_ptr<UDPTrackerRequest> createAnnounce(const std::string& remoteAddr,
  28. uint16_t remotePort,
  29. uint32_t transactionId)
  30. {
  31. std::shared_ptr<UDPTrackerRequest> req(new UDPTrackerRequest());
  32. req->connectionId = std::numeric_limits<uint64_t>::max();
  33. req->action = UDPT_ACT_ANNOUNCE;
  34. req->remoteAddr = remoteAddr;
  35. req->remotePort = remotePort;
  36. req->transactionId = transactionId;
  37. req->infohash = "bittorrent-infohash-";
  38. req->peerId = "bittorrent-peer-id--";
  39. req->downloaded = INT64_MAX - 1;
  40. req->left = INT64_MAX - 2;
  41. req->uploaded = INT64_MAX - 3;
  42. req->event = UDPT_EVT_STARTED;
  43. req->ip = 0;
  44. req->key = 1000000007;
  45. req->numWant = 50;
  46. req->port = 6889;
  47. req->extensions = 0;
  48. return req;
  49. }
  50. } // namespace
  51. namespace {
  52. ssize_t createErrorReply(unsigned char* data, size_t len,
  53. uint32_t transactionId, const std::string& errorString)
  54. {
  55. bittorrent::setIntParam(data, UDPT_ACT_ERROR);
  56. bittorrent::setIntParam(data + 4, transactionId);
  57. memcpy(data + 8, errorString.c_str(), errorString.size());
  58. return 8 + errorString.size();
  59. }
  60. } // namespace
  61. namespace {
  62. ssize_t createConnectReply(unsigned char* data, size_t len,
  63. uint64_t connectionId, uint32_t transactionId)
  64. {
  65. bittorrent::setIntParam(data, UDPT_ACT_CONNECT);
  66. bittorrent::setIntParam(data + 4, transactionId);
  67. bittorrent::setLLIntParam(data + 8, connectionId);
  68. return 16;
  69. }
  70. } // namespace
  71. namespace {
  72. ssize_t createAnnounceReply(unsigned char* data, size_t len,
  73. uint32_t transactionId, int numPeers = 0)
  74. {
  75. bittorrent::setIntParam(data, UDPT_ACT_ANNOUNCE);
  76. bittorrent::setIntParam(data + 4, transactionId);
  77. bittorrent::setIntParam(data + 8, 1800);
  78. bittorrent::setIntParam(data + 12, 100);
  79. bittorrent::setIntParam(data + 16, 256);
  80. for (int i = 0; i < numPeers; ++i) {
  81. bittorrent::packcompact(data + 20 + 6 * i,
  82. "192.168.0." + util::uitos(i + 1), 6990 + i);
  83. }
  84. return 20 + 6 * numPeers;
  85. }
  86. } // namespace
  87. void UDPTrackerClientTest::testCreateUDPTrackerConnect()
  88. {
  89. unsigned char data[16];
  90. std::string remoteAddr;
  91. uint16_t remotePort = 0;
  92. std::shared_ptr<UDPTrackerRequest> req(new UDPTrackerRequest());
  93. req->action = UDPT_ACT_CONNECT;
  94. req->remoteAddr = "192.168.0.1";
  95. req->remotePort = 6991;
  96. req->transactionId = 1000000009;
  97. ssize_t rv =
  98. createUDPTrackerConnect(data, sizeof(data), remoteAddr, remotePort, req);
  99. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  100. CPPUNIT_ASSERT_EQUAL(req->remoteAddr, remoteAddr);
  101. CPPUNIT_ASSERT_EQUAL(req->remotePort, remotePort);
  102. CPPUNIT_ASSERT_EQUAL((int64_t)UDPT_INITIAL_CONNECTION_ID,
  103. (int64_t)bittorrent::getLLIntParam(data, 0));
  104. CPPUNIT_ASSERT_EQUAL((int)req->action, (int)bittorrent::getIntParam(data, 8));
  105. CPPUNIT_ASSERT_EQUAL(req->transactionId, bittorrent::getIntParam(data, 12));
  106. }
  107. void UDPTrackerClientTest::testCreateUDPTrackerAnnounce()
  108. {
  109. unsigned char data[100];
  110. std::string remoteAddr;
  111. uint16_t remotePort = 0;
  112. std::shared_ptr<UDPTrackerRequest> req(
  113. createAnnounce("192.168.0.1", 6991, 1000000009));
  114. ssize_t rv =
  115. createUDPTrackerAnnounce(data, sizeof(data), remoteAddr, remotePort, req);
  116. CPPUNIT_ASSERT_EQUAL((ssize_t)100, rv);
  117. CPPUNIT_ASSERT_EQUAL(req->connectionId, bittorrent::getLLIntParam(data, 0));
  118. CPPUNIT_ASSERT_EQUAL((int)req->action, (int)bittorrent::getIntParam(data, 8));
  119. CPPUNIT_ASSERT_EQUAL(req->transactionId, bittorrent::getIntParam(data, 12));
  120. CPPUNIT_ASSERT_EQUAL(req->infohash, std::string(&data[16], &data[36]));
  121. CPPUNIT_ASSERT_EQUAL(req->peerId, std::string(&data[36], &data[56]));
  122. CPPUNIT_ASSERT_EQUAL(req->downloaded,
  123. (int64_t)bittorrent::getLLIntParam(data, 56));
  124. CPPUNIT_ASSERT_EQUAL(req->left, (int64_t)bittorrent::getLLIntParam(data, 64));
  125. CPPUNIT_ASSERT_EQUAL(req->uploaded,
  126. (int64_t)bittorrent::getLLIntParam(data, 72));
  127. CPPUNIT_ASSERT_EQUAL(req->event, (int32_t)bittorrent::getIntParam(data, 80));
  128. CPPUNIT_ASSERT_EQUAL(req->ip, bittorrent::getIntParam(data, 84));
  129. CPPUNIT_ASSERT_EQUAL(req->key, bittorrent::getIntParam(data, 88));
  130. CPPUNIT_ASSERT_EQUAL(req->numWant,
  131. (int32_t)bittorrent::getIntParam(data, 92));
  132. CPPUNIT_ASSERT_EQUAL(req->port, bittorrent::getShortIntParam(data, 96));
  133. CPPUNIT_ASSERT_EQUAL(req->extensions, bittorrent::getShortIntParam(data, 98));
  134. }
  135. void UDPTrackerClientTest::testConnectFollowedByAnnounce()
  136. {
  137. ssize_t rv;
  138. UDPTrackerClient tr;
  139. unsigned char data[100];
  140. std::string remoteAddr;
  141. uint16_t remotePort;
  142. Timer now;
  143. std::shared_ptr<UDPTrackerRequest> recvReq;
  144. std::shared_ptr<UDPTrackerRequest> req1(
  145. createAnnounce("192.168.0.1", 6991, 0));
  146. std::shared_ptr<UDPTrackerRequest> req2(
  147. createAnnounce("192.168.0.1", 6991, 0));
  148. req2->infohash = "bittorrent-infohash2";
  149. tr.addRequest(req1);
  150. tr.addRequest(req2);
  151. CPPUNIT_ASSERT_EQUAL((size_t)2, tr.getPendingRequests().size());
  152. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  153. // CONNECT request was inserted
  154. CPPUNIT_ASSERT_EQUAL((size_t)3, tr.getPendingRequests().size());
  155. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  156. CPPUNIT_ASSERT_EQUAL(req1->remoteAddr, remoteAddr);
  157. CPPUNIT_ASSERT_EQUAL(req1->remotePort, remotePort);
  158. CPPUNIT_ASSERT_EQUAL((int64_t)UDPT_INITIAL_CONNECTION_ID,
  159. (int64_t)bittorrent::getLLIntParam(data, 0));
  160. uint32_t transactionId = bittorrent::getIntParam(data, 12);
  161. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  162. // Duplicate CONNECT request was not inserted
  163. CPPUNIT_ASSERT_EQUAL((size_t)3, tr.getPendingRequests().size());
  164. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  165. tr.requestSent(now);
  166. // CONNECT request was moved to inflight
  167. CPPUNIT_ASSERT_EQUAL((size_t)2, tr.getPendingRequests().size());
  168. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  169. // Now all pending requests were moved to connect
  170. CPPUNIT_ASSERT_EQUAL((ssize_t)-1, rv);
  171. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  172. uint64_t connectionId = 12345;
  173. rv = createConnectReply(data, sizeof(data), connectionId, transactionId);
  174. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  175. now);
  176. CPPUNIT_ASSERT_EQUAL(0, (int)rv);
  177. if (rv == 0) {
  178. CPPUNIT_ASSERT_EQUAL((int32_t)UDPT_ACT_CONNECT, recvReq->action);
  179. }
  180. // Now 2 requests get back to pending
  181. CPPUNIT_ASSERT_EQUAL((size_t)2, tr.getPendingRequests().size());
  182. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  183. // Creates announce for req1
  184. CPPUNIT_ASSERT_EQUAL((ssize_t)100, rv);
  185. CPPUNIT_ASSERT_EQUAL((size_t)2, tr.getPendingRequests().size());
  186. CPPUNIT_ASSERT_EQUAL(connectionId, bittorrent::getLLIntParam(data, 0));
  187. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_ANNOUNCE,
  188. (int)bittorrent::getIntParam(data, 8));
  189. CPPUNIT_ASSERT_EQUAL(req1->infohash, std::string(&data[16], &data[36]));
  190. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  191. // Don't duplicate same request data
  192. CPPUNIT_ASSERT_EQUAL((ssize_t)100, rv);
  193. CPPUNIT_ASSERT_EQUAL((size_t)2, tr.getPendingRequests().size());
  194. uint32_t transactionId1 = bittorrent::getIntParam(data, 12);
  195. tr.requestSent(now);
  196. CPPUNIT_ASSERT_EQUAL((size_t)1, tr.getPendingRequests().size());
  197. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  198. uint32_t transactionId2 = bittorrent::getIntParam(data, 12);
  199. // Creates announce for req2
  200. CPPUNIT_ASSERT_EQUAL((ssize_t)100, rv);
  201. CPPUNIT_ASSERT_EQUAL((size_t)1, tr.getPendingRequests().size());
  202. CPPUNIT_ASSERT_EQUAL(connectionId, bittorrent::getLLIntParam(data, 0));
  203. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_ANNOUNCE,
  204. (int)bittorrent::getIntParam(data, 8));
  205. CPPUNIT_ASSERT_EQUAL(req2->infohash, std::string(&data[16], &data[36]));
  206. tr.requestSent(now);
  207. // Now all requests are inflight
  208. CPPUNIT_ASSERT_EQUAL((size_t)0, tr.getPendingRequests().size());
  209. // Reply for req2
  210. rv = createAnnounceReply(data, sizeof(data), transactionId2);
  211. rv = tr.receiveReply(recvReq, data, rv, req2->remoteAddr, req2->remotePort,
  212. now);
  213. CPPUNIT_ASSERT_EQUAL(0, (int)rv);
  214. if (rv == 0) {
  215. CPPUNIT_ASSERT_EQUAL((int32_t)UDPT_ACT_ANNOUNCE, recvReq->action);
  216. }
  217. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req2->state);
  218. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_SUCCESS, req2->error);
  219. // Reply for req1
  220. rv = createAnnounceReply(data, sizeof(data), transactionId1, 2);
  221. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  222. now);
  223. CPPUNIT_ASSERT_EQUAL(0, (int)rv);
  224. if (rv == 0) {
  225. CPPUNIT_ASSERT_EQUAL((int32_t)UDPT_ACT_ANNOUNCE, recvReq->action);
  226. }
  227. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  228. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_SUCCESS, req1->error);
  229. CPPUNIT_ASSERT_EQUAL((size_t)2, req1->reply->peers.size());
  230. for (int i = 0; i < 2; ++i) {
  231. CPPUNIT_ASSERT_EQUAL("192.168.0." + util::uitos(i + 1),
  232. req1->reply->peers[i].first);
  233. CPPUNIT_ASSERT_EQUAL((uint16_t)(6990 + i), req1->reply->peers[i].second);
  234. }
  235. // Since we have connection ID, next announce request can be sent
  236. // immediately
  237. std::shared_ptr<UDPTrackerRequest> req3(
  238. createAnnounce("192.168.0.1", 6991, 0));
  239. req3->infohash = "bittorrent-infohash3";
  240. tr.addRequest(req3);
  241. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  242. CPPUNIT_ASSERT_EQUAL((ssize_t)100, rv);
  243. CPPUNIT_ASSERT_EQUAL(req3->infohash, std::string(&data[16], &data[36]));
  244. tr.requestSent(now);
  245. std::shared_ptr<UDPTrackerRequest> req4(
  246. createAnnounce("192.168.0.1", 6991, 0));
  247. req4->infohash = "bittorrent-infohash4";
  248. tr.addRequest(req4);
  249. Timer future = now;
  250. future.advance(1_h);
  251. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, future);
  252. // connection ID is stale because of the timeout
  253. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  254. CPPUNIT_ASSERT_EQUAL((int64_t)UDPT_INITIAL_CONNECTION_ID,
  255. (int64_t)bittorrent::getLLIntParam(data, 0));
  256. }
  257. void UDPTrackerClientTest::testRequestFailure()
  258. {
  259. ssize_t rv;
  260. UDPTrackerClient tr;
  261. unsigned char data[100];
  262. std::string remoteAddr;
  263. uint16_t remotePort;
  264. Timer now;
  265. std::shared_ptr<UDPTrackerRequest> recvReq;
  266. {
  267. std::shared_ptr<UDPTrackerRequest> req1(
  268. createAnnounce("192.168.0.1", 6991, 0));
  269. std::shared_ptr<UDPTrackerRequest> req2(
  270. createAnnounce("192.168.0.1", 6991, 0));
  271. tr.addRequest(req1);
  272. tr.addRequest(req2);
  273. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  274. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  275. (int)bittorrent::getIntParam(data, 8));
  276. tr.requestFail(UDPT_ERR_NETWORK);
  277. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  278. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_NETWORK, req1->error);
  279. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req2->state);
  280. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_NETWORK, req2->error);
  281. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  282. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  283. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  284. }
  285. {
  286. std::shared_ptr<UDPTrackerRequest> req1(
  287. createAnnounce("192.168.0.1", 6991, 0));
  288. std::shared_ptr<UDPTrackerRequest> req2(
  289. createAnnounce("192.168.0.1", 6991, 0));
  290. tr.addRequest(req1);
  291. tr.addRequest(req2);
  292. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  293. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  294. (int)bittorrent::getIntParam(data, 8));
  295. uint32_t transactionId = bittorrent::getIntParam(data, 12);
  296. tr.requestSent(now);
  297. rv = createErrorReply(data, sizeof(data), transactionId, "error");
  298. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  299. now);
  300. CPPUNIT_ASSERT_EQUAL((ssize_t)0, rv);
  301. if (rv == 0) {
  302. CPPUNIT_ASSERT_EQUAL((int32_t)UDPT_ACT_CONNECT, recvReq->action);
  303. }
  304. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  305. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TRACKER, req1->error);
  306. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req2->state);
  307. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TRACKER, req2->error);
  308. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  309. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  310. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  311. }
  312. {
  313. std::shared_ptr<UDPTrackerRequest> req1(
  314. createAnnounce("192.168.0.1", 6991, 0));
  315. tr.addRequest(req1);
  316. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  317. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  318. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  319. (int)bittorrent::getIntParam(data, 8));
  320. uint32_t transactionId = bittorrent::getIntParam(data, 12);
  321. tr.requestSent(now);
  322. uint64_t connectionId = 12345;
  323. rv = createConnectReply(data, sizeof(data), connectionId, transactionId);
  324. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  325. now);
  326. CPPUNIT_ASSERT_EQUAL(0, (int)rv);
  327. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  328. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_ANNOUNCE,
  329. (int)bittorrent::getIntParam(data, 8));
  330. transactionId = bittorrent::getIntParam(data, 12);
  331. tr.requestSent(now);
  332. rv = createErrorReply(data, sizeof(data), transactionId, "announce error");
  333. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  334. now);
  335. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  336. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TRACKER, req1->error);
  337. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  338. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  339. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  340. }
  341. }
  342. void UDPTrackerClientTest::testTimeout()
  343. {
  344. ssize_t rv;
  345. unsigned char data[100];
  346. std::string remoteAddr;
  347. uint16_t remotePort;
  348. Timer now;
  349. UDPTrackerClient tr;
  350. std::shared_ptr<UDPTrackerRequest> recvReq;
  351. {
  352. std::shared_ptr<UDPTrackerRequest> req1(
  353. createAnnounce("192.168.0.1", 6991, 0));
  354. std::shared_ptr<UDPTrackerRequest> req2(
  355. createAnnounce("192.168.0.1", 6991, 0));
  356. tr.addRequest(req1);
  357. tr.addRequest(req2);
  358. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  359. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  360. (int)bittorrent::getIntParam(data, 8));
  361. tr.requestSent(now);
  362. now.advance(20_s);
  363. // 15 seconds 1st stage timeout passed
  364. tr.handleTimeout(now);
  365. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  366. CPPUNIT_ASSERT_EQUAL((size_t)3, tr.getPendingRequests().size());
  367. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  368. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  369. // CONNECT request was inserted
  370. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  371. (int)bittorrent::getIntParam(data, 8));
  372. tr.requestSent(now);
  373. now.advance(65_s);
  374. // 60 seconds 2nd stage timeout passed
  375. tr.handleTimeout(now);
  376. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  377. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  378. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  379. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  380. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TIMEOUT, req1->error);
  381. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req2->state);
  382. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TIMEOUT, req2->error);
  383. }
  384. {
  385. std::shared_ptr<UDPTrackerRequest> req1(
  386. createAnnounce("192.168.0.1", 6991, 0));
  387. tr.addRequest(req1);
  388. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  389. CPPUNIT_ASSERT_EQUAL((ssize_t)16, rv);
  390. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_CONNECT,
  391. (int)bittorrent::getIntParam(data, 8));
  392. uint32_t transactionId = bittorrent::getIntParam(data, 12);
  393. tr.requestSent(now);
  394. uint64_t connectionId = 12345;
  395. rv = createConnectReply(data, sizeof(data), connectionId, transactionId);
  396. rv = tr.receiveReply(recvReq, data, rv, req1->remoteAddr, req1->remotePort,
  397. now);
  398. CPPUNIT_ASSERT_EQUAL(0, (int)rv);
  399. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  400. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_ANNOUNCE,
  401. (int)bittorrent::getIntParam(data, 8));
  402. tr.requestSent(now);
  403. now.advance(20_s);
  404. // 15 seconds 1st stage timeout passed
  405. tr.handleTimeout(now);
  406. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  407. CPPUNIT_ASSERT_EQUAL((size_t)1, tr.getPendingRequests().size());
  408. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  409. rv = tr.createRequest(data, sizeof(data), remoteAddr, remotePort, now);
  410. CPPUNIT_ASSERT_EQUAL((int)UDPT_ACT_ANNOUNCE,
  411. (int)bittorrent::getIntParam(data, 8));
  412. tr.requestSent(now);
  413. now.advance(65_s);
  414. // 60 seconds 2nd stage timeout passed
  415. tr.handleTimeout(now);
  416. CPPUNIT_ASSERT(tr.getConnectRequests().empty());
  417. CPPUNIT_ASSERT(tr.getPendingRequests().empty());
  418. CPPUNIT_ASSERT(tr.getInflightRequests().empty());
  419. CPPUNIT_ASSERT_EQUAL((int)UDPT_STA_COMPLETE, req1->state);
  420. CPPUNIT_ASSERT_EQUAL((int)UDPT_ERR_TIMEOUT, req1->error);
  421. }
  422. }
  423. } // namespace aria2