From e3eb0d2eda0bb8c4decf9bc56b025157e70387c2 Mon Sep 17 00:00:00 2001 From: Jesper Jensen Date: Sat, 2 Oct 2021 00:25:37 +0200 Subject: Add timeout handling --- test/proto.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- test/routing.c | 58 +++++++++++++++++++++--- 2 files changed, 183 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/proto.c b/test/proto.c index 3becc98..03a4a45 100644 --- a/test/proto.c +++ b/test/proto.c @@ -12,7 +12,7 @@ void test_begin_pings_bootstrap_node() { dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; struct message* message_cursor = outbuff; - proto_begin(&dht, &message_cursor, outbuff+10); + proto_begin(&dht, time(NULL), &message_cursor, outbuff+10); TEST_ASSERT_EQUAL_PTR(message_cursor, outbuff+1); TEST_ASSERT_EQUAL(91, outbuff[0].payload_len); @@ -30,14 +30,14 @@ void test_response_from_initial_probe() { dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; { struct message* message_cursor = outbuff; - proto_begin(&dht, &message_cursor, outbuff+2); + proto_begin(&dht, time(NULL), &message_cursor, outbuff+2); remote_len = outbuff[0].dest_len; memcpy(&remote, &outbuff[0].dest, remote_len); } char buff[] = "d1:y1:r1:t1:01:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:nodes26:bbbbbbbbbbbbbbbbbbbb\xFF\xFF\xFF\xFF\x00\x00""ee"; struct message* message_cursor = outbuff; - proto_run(&dht, buff, sizeof(buff), (struct sockaddr_in*)&remote, remote_len, &message_cursor, outbuff+2); + proto_run(&dht, buff, sizeof(buff), (struct sockaddr_in*)&remote, remote_len, 10, &message_cursor, outbuff+2); TEST_ASSERT_EQUAL_PTR_MESSAGE(message_cursor, outbuff+1, "Sends one packet"); TEST_ASSERT_EQUAL(91, outbuff[0].payload_len); @@ -50,6 +50,7 @@ void test_response_from_initial_probe() { TEST_ASSERT_NOT_NULL(entry); TEST_ASSERT_EQUAL(((struct sockaddr_in*)&remote)->sin_addr.s_addr, entry->addr.ip); TEST_ASSERT_EQUAL(((struct sockaddr_in*)&remote)->sin_port, entry->addr.port); + TEST_ASSERT_EQUAL(PROTO_UNCTM+10, entry->expire); } void test_reponse_from_wrong_ip() { @@ -59,7 +60,7 @@ void test_reponse_from_wrong_ip() { dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; { struct message* message_cursor = outbuff; - proto_begin(&dht, &message_cursor, outbuff+2); + proto_begin(&dht, time(NULL), &message_cursor, outbuff+2); } // This is fragile, since the ip of the bootstrap node could change, and we @@ -72,7 +73,7 @@ void test_reponse_from_wrong_ip() { char buff[] = "d1:y1:r1:t1:01:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:nodes26:bbbbbbbbbbbbbbbbbbbb\xFF\xFF\xFF\xFF\x00\x00""ee"; struct message* message_cursor = outbuff; - proto_run(&dht, buff, sizeof(buff), &remote, sizeof(remote), &message_cursor, outbuff+2); + proto_run(&dht, buff, sizeof(buff), &remote, sizeof(remote), 0, &message_cursor, outbuff+2); // We shouldn't send any packets, since the response is rejected TEST_ASSERT_EQUAL_PTR(message_cursor, outbuff); @@ -91,7 +92,7 @@ void test_ping() { dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; { struct message* message_cursor = outbuff; - proto_begin(&dht, &message_cursor, outbuff+2); + proto_begin(&dht, time(NULL), &message_cursor, outbuff+2); } struct sockaddr_in remote; @@ -101,7 +102,7 @@ void test_ping() { char buff[] = "d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe"; struct message* message_cursor = outbuff; - proto_run(&dht, buff, sizeof(buff), &remote, sizeof(remote), &message_cursor, outbuff+2); + proto_run(&dht, buff, sizeof(buff), &remote, sizeof(remote), 0, &message_cursor, outbuff+2); // We should have sent a response TEST_ASSERT_EQUAL_PTR(message_cursor, outbuff+1); @@ -109,3 +110,126 @@ void test_ping() { TEST_ASSERT_EQUAL(48, outbuff[0].payload_len); TEST_ASSERT_EQUAL_CHAR_ARRAY("d1:t2:aa1:y1:r1:rd2:id20:BBBBBBBBBBBBBBBBBBBBee", outbuff[0].payload, 47); } + +void test_note_times_out() { + routing_flush(); + struct message outbuff[2] = {0}; + + struct sockaddr_storage remote; + socklen_t remote_len; + + struct dht dht; + dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; + { + struct message* message_cursor = outbuff; + proto_begin(&dht, 0, &message_cursor, outbuff+2); + remote_len = outbuff[0].dest_len; + memcpy(&remote, &outbuff[0].dest, remote_len); + } + + // The node responds to the ping at t=5 + { + char buff[] = "d1:y1:r1:t1:01:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:nodes26:bbbbbbbbbbbbbbbbbbbb\xFF\xFF\xFF\xFF\x00\x00""ee"; + struct message* message_cursor = outbuff; + proto_run(&dht, buff, sizeof(buff), (struct sockaddr_in*)&remote, remote_len, 5, &message_cursor, outbuff+2); + } + + // 15 minutes later a timeout is fired + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)&remote, remote_len, 905, &message_cursor, outbuff+2); + + // Which should create a retry ping and a ping for the (now) uncertain node + TEST_ASSERT_EQUAL_PTR(message_cursor, outbuff+2); + TEST_ASSERT_EQUAL(91, outbuff[1].payload_len); + TEST_ASSERT_EQUAL_CHAR_ARRAY("d1:ad2:id20:BBBBBBBBBBBBBBBBBBBB6:target20:", outbuff[1].payload, 43); + TEST_ASSERT_EQUAL_CHAR_ARRAY("e1:q9:find_node1:t1:01:y1:qe", outbuff[1].payload+63, 28); +} + +void test_response_after_retry() { + struct message outbuff[10] = {0}; + + struct dht dht; + dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; + + { + struct message* message_cursor = outbuff; + proto_begin(&dht, 0, &message_cursor, outbuff+2); + } + + // After TMOUT seconds we retry the ping + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, PROTO_TMOUT, &message_cursor, outbuff+2); + + TEST_ASSERT_EQUAL_PTR(message_cursor, outbuff+1); + TEST_ASSERT_EQUAL(91, outbuff[0].payload_len); + TEST_ASSERT_EQUAL_CHAR_ARRAY("d1:ad2:id20:BBBBBBBBBBBBBBBBBBBB6:target20:", outbuff[0].payload, 43); + TEST_ASSERT_EQUAL_CHAR_ARRAY("e1:q9:find_node1:t1:01:y1:qe", outbuff[0].payload+63, 28); +} + +void test_remove_from_routing_after_3_retries() { + struct message outbuff[10] = {0}; + time_t now = 0; + + struct sockaddr_storage remote; + socklen_t remote_len; + + struct dht dht; + dht.self = (struct nodeid){.inner={0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242}}; + struct nodeid other = (struct nodeid){.inner={0x61616161, 0x61616161, 0x61616161, 0x61616161, 0x61616161}}; + + { + struct message* message_cursor = outbuff; + proto_begin(&dht, 0, &message_cursor, outbuff+2); + remote_len = outbuff[0].dest_len; + memcpy(&remote, &outbuff[0].dest, remote_len); + } + now += 10; + + { + // The node responds + // We return no new nodes to stop any new pings from going out + char buff[] = "d1:y1:r1:t1:01:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:nodes0:""ee"; + struct message* message_cursor = outbuff; + proto_run(&dht, buff, sizeof(buff), (struct sockaddr_in*)&remote, remote_len, now, &message_cursor, outbuff+2); + } + struct entry* entry = routing_get(&other); + TEST_ASSERT_NOT_NULL(entry); + + now += PROTO_UNCTM; + { + // The node becomes uncertain + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, now, &message_cursor, outbuff+2); + TEST_ASSERT_EQUAL_PTR_MESSAGE(message_cursor, outbuff+1, "Ping was not sent"); + } + + now += PROTO_TMOUT; + { + // 1st retry + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, now, &message_cursor, outbuff+2); + } + + now += PROTO_TMOUT; + { + // 2nd retry + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, now, &message_cursor, outbuff+2); + } + + now += PROTO_TMOUT; + { + // 3rd retry + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, now, &message_cursor, outbuff+2); + } + + now += PROTO_TMOUT; + // Drop the node + struct message* message_cursor = outbuff; + proto_run(&dht, NULL, 0, (struct sockaddr_in*)NULL, 0, now, &message_cursor, outbuff+2); + + TEST_ASSERT_EQUAL_PTR_MESSAGE(message_cursor, outbuff, "The timeout should send a message"); + entry = routing_get(&other); + TEST_ASSERT_NULL(entry); +} diff --git a/test/routing.c b/test/routing.c index 7905bc0..eb899ba 100644 --- a/test/routing.c +++ b/test/routing.c @@ -36,7 +36,7 @@ void test_can_find_added() { // Set the entries entry->addr = addr; - entry->last = time(NULL); + entry->expire = time(NULL); // Ask for 3 nodes struct entry *out[3] = {0}; @@ -65,7 +65,7 @@ void test_discard_offer_when_bucket_full() { // Set the entries entry->addr = addr; - entry->last = time(NULL); + entry->expire = time(NULL); new.inner[4] += 1; } @@ -86,7 +86,7 @@ void test_discard_offer_when_nodeid_added_twice() { struct entry* entry; TEST_ASSERT_TRUE(routing_offer(&new, &entry)); entry->addr = addr; - entry->last = time(NULL); + entry->expire = time(NULL); bool accept = routing_offer(&new, &entry); TEST_ASSERT_FALSE_MESSAGE(accept, "Accepted entry when bucket was full"); @@ -112,7 +112,7 @@ void test_not_interested_when_nodeid_in_table() { struct entry* entry; TEST_ASSERT_TRUE(routing_offer(&new, &entry)); entry->addr = (struct addr){.ip = IP(128,0,0,1), .port = 0}; - entry->last = time(NULL); + entry->expire = time(NULL); bool interest = routing_interested(&new); TEST_ASSERT_FALSE_MESSAGE(interest, "Was interested in node"); @@ -135,7 +135,7 @@ void test_not_interested_when_bucket_is_full() { // Set the entries entry->addr = addr; - entry->last = time(NULL); + entry->expire = time(NULL); new.inner[4] += 1; } @@ -162,7 +162,7 @@ void test_lowest_ts_is_oldest() { entry->id = new; entry->addr = addr; // Invert the timestamps to make the last one have lowest timestamp - entry->last = 2-i; + entry->expire = 2-i; new.inner_b[19] += 1; } @@ -173,3 +173,49 @@ void test_lowest_ts_is_oldest() { TEST_ASSERT_NOT_NULL(dest); TEST_ASSERT_EQUAL(1, dest->id.inner_b[19]); } + +void test_get_after_offer() { + routing_flush(); + + // The address we are going to store + struct addr addr = (struct addr){.ip = IP(128,0,0,1), .port = 0}; + + // Make a nodeid that is one bit different + struct nodeid new = self; + + new.inner[4] += 1; + struct entry* entry; + TEST_ASSERT_TRUE_MESSAGE(routing_offer(&new, &entry), "Did not accept new entry"); + + // Set the entry + entry->addr = addr; + entry->expire = 10; + + struct entry* e = routing_get(&new); + + TEST_ASSERT_NOT_NULL(e); + TEST_ASSERT_EQUAL_MEMORY(&addr, &e->addr, sizeof(struct addr)); +} + +void test_get_after_offer_and_remove() { + routing_flush(); + + // The address we are going to store + struct addr addr = (struct addr){.ip = IP(128,0,0,1), .port = 0}; + + // Make a nodeid that is one bit different + struct nodeid new = self; + + new.inner[4] += 1; + struct entry* entry; + TEST_ASSERT_TRUE_MESSAGE(routing_offer(&new, &entry), "Did not accept new entry"); + + // Set the entry + entry->addr = addr; + entry->expire = 10; + + routing_remove(&new); + struct entry* e = routing_get(&new); + + TEST_ASSERT_NULL(e); +} -- cgit v1.2.3