#include "tracker.h" #include #include #include #include static void put32(uint8_t *p, uint32_t v) { p[0] = (uint8_t)(v >> 24); p[1] = (uint8_t)(v >> 16); p[2] = (uint8_t)(v >> 8); p[3] = (uint8_t)v; } static void put64(uint8_t *p, uint64_t v) { put32(p, (uint32_t)(v >> 32)); put32(p + 4, (uint32_t)v); } static uint32_t get32(const uint8_t *p) { return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3]; } static void fill_announce(tracker_announce_request *req, const char *hash, const char *peer_id, uint16_t port, uint64_t left, tracker_event event) { memset(req, 0, sizeof(*req)); memcpy(req->info_hash, hash, 20); memcpy(req->peer_id, peer_id, 20); req->port = port; req->left = left; req->numwant = -1; req->event = event; req->compact = 1; req->has_key = 1; req->key = (uint32_t)port; } static tracker_peer ipv4_source(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { tracker_peer peer; memset(&peer, 0, sizeof(peer)); peer.family = TRACKER_ADDR_IPV4; peer.addr[0] = a; peer.addr[1] = b; peer.addr[2] = c; peer.addr[3] = d; return peer; } static void test_dht_queries(void) { uint8_t buf[512]; size_t written = 0; dht_message msg; uint8_t tx[] = {'a', 'a'}; uint8_t id[20] = "abcdefghij0123456789"; uint8_t target[20] = "mnopqrstuvwxyz123456"; uint8_t token[] = "tok"; assert(dht_write_ping_query(tx, sizeof(tx), id, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.type == DHT_MSG_QUERY); assert(msg.query == DHT_QUERY_PING); assert(msg.transaction_len == 2); assert(memcmp(msg.transaction, tx, 2) == 0); assert(memcmp(msg.id, id, 20) == 0); assert(dht_write_find_node_query(tx, sizeof(tx), id, target, 1, 1, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.query == DHT_QUERY_FIND_NODE); assert(memcmp(msg.target, target, 20) == 0); assert(msg.want_ipv4 == 1); assert(msg.want_ipv6 == 1); assert(dht_write_get_peers_query(tx, sizeof(tx), id, target, 0, 1, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.query == DHT_QUERY_GET_PEERS); assert(memcmp(msg.info_hash, target, 20) == 0); assert(msg.want_ipv4 == 0); assert(msg.want_ipv6 == 1); assert(dht_write_announce_peer_query(tx, sizeof(tx), id, target, 6881, token, sizeof(token) - 1, 1, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.query == DHT_QUERY_ANNOUNCE_PEER); assert(memcmp(msg.info_hash, target, 20) == 0); assert(msg.port == 6881); assert(msg.implied_port == 1); assert(msg.token_len == sizeof(token) - 1); assert(memcmp(msg.token, token, sizeof(token) - 1) == 0); } static void test_dht_responses(void) { uint8_t buf[1024]; size_t written = 0; dht_message msg; uint8_t tx[] = {'b', 'b'}; uint8_t id[20] = "abcdefghij0123456789"; uint8_t node_id[20] = "mnopqrstuvwxyz123456"; uint8_t token[] = "aoeusnth"; dht_node nodes[2]; tracker_peer peers[2]; assert(dht_write_ping_response(tx, sizeof(tx), id, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.type == DHT_MSG_RESPONSE); assert(memcmp(msg.id, id, 20) == 0); memset(nodes, 0, sizeof(nodes)); memcpy(nodes[0].id, node_id, 20); nodes[0].family = TRACKER_ADDR_IPV4; nodes[0].addr[0] = 1; nodes[0].addr[1] = 2; nodes[0].addr[2] = 3; nodes[0].addr[3] = 4; nodes[0].port = 6881; memcpy(nodes[1].id, id, 20); nodes[1].family = TRACKER_ADDR_IPV6; nodes[1].addr[15] = 1; nodes[1].port = 6882; assert(dht_write_nodes_response(tx, sizeof(tx), id, token, sizeof(token) - 1, nodes, 2, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.type == DHT_MSG_RESPONSE); assert(msg.node_count == 2); assert(msg.nodes[0].family == TRACKER_ADDR_IPV4); assert(msg.nodes[0].port == 6881); assert(msg.nodes[1].family == TRACKER_ADDR_IPV6); assert(msg.nodes[1].port == 6882); assert(msg.token_len == sizeof(token) - 1); assert(memcmp(msg.token, token, sizeof(token) - 1) == 0); memset(peers, 0, sizeof(peers)); peers[0].family = TRACKER_ADDR_IPV4; peers[0].addr[0] = 8; peers[0].addr[1] = 8; peers[0].addr[2] = 8; peers[0].addr[3] = 8; peers[0].port = 51413; peers[1].family = TRACKER_ADDR_IPV6; peers[1].addr[15] = 2; peers[1].port = 51414; assert(dht_write_peers_response(tx, sizeof(tx), id, token, sizeof(token) - 1, peers, 2, buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.peer_count == 2); assert(msg.peers[0].family == TRACKER_ADDR_IPV4); assert(msg.peers[0].port == 51413); assert(msg.peers[1].family == TRACKER_ADDR_IPV6); assert(msg.peers[1].port == 51414); } static void test_dht_error(void) { uint8_t buf[256]; size_t written = 0; dht_message msg; uint8_t tx[] = {'e', 'r'}; assert(dht_write_error(tx, sizeof(tx), DHT_ERR_PROTOCOL, "bad token", buf, sizeof(buf), &written) == TRACKER_OK); assert(dht_parse_message(buf, written, &msg) == TRACKER_OK); assert(msg.type == DHT_MSG_ERROR); assert(msg.error_code == DHT_ERR_PROTOCOL); assert(strcmp(msg.error_message, "bad token") == 0); } static void test_http_announce_parse(void) { tracker_announce_request req; const char *q = "/announce?info_hash=%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13" "&peer_id=-TT0001-abcdefghijkl" "&port=6881&uploaded=10&downloaded=20&left=30&compact=1" "&event=started&numwant=50&key=12345&trackerid=session"; int rc = tracker_http_parse_announce_query(q, &req); assert(rc == TRACKER_OK); assert(req.info_hash[0] == 0); assert(req.info_hash[19] == 0x13); assert(memcmp(req.peer_id, "-TT0001-abcdefghijkl", 20) == 0); assert(req.port == 6881); assert(req.uploaded == 10); assert(req.downloaded == 20); assert(req.left == 30); assert(req.compact == 1); assert(req.event == TRACKER_EVENT_STARTED); assert(req.numwant == 50); assert(req.has_key == 1 && req.key == 12345); assert(strcmp(req.tracker_id, "session") == 0); assert(tracker_http_parse_announce_query( "/announce?info_hash=++++++++++++++++++++" "&peer_id=--------------------&port=1&uploaded=0" "&downloaded=0&left=0", &req) == TRACKER_OK); assert(req.info_hash[0] == '+'); assert(req.info_hash[19] == '+'); } static void test_http_compact_response(void) { uint8_t buf[512]; size_t written = 0; tracker_peer peers[2]; tracker_announce_response resp; memset(peers, 0, sizeof(peers)); peers[0].family = TRACKER_ADDR_IPV4; peers[0].addr[0] = 127; peers[0].addr[1] = 0; peers[0].addr[2] = 0; peers[0].addr[3] = 1; peers[0].port = 6881; peers[1].family = TRACKER_ADDR_IPV6; peers[1].addr[15] = 1; peers[1].port = 51413; memset(&resp, 0, sizeof(resp)); resp.interval = 1800; resp.complete = 7; resp.incomplete = 3; resp.peers = peers; resp.peer_count = 2; resp.compact = 1; assert(tracker_http_write_announce_response(&resp, buf, sizeof(buf), &written) == TRACKER_OK); assert(written > 0); assert(memmem(buf, written, "5:peers6:", 9) != NULL); assert(memmem(buf, written, "6:peers618:", 10) != NULL); } static void test_http_scrape(void) { uint8_t hashes[2][20]; size_t count = 0; tracker_scrape_file files[1]; tracker_scrape_response resp; uint8_t buf[256]; size_t written = 0; int rc = tracker_http_parse_scrape_query( "/scrape?info_hash=aaaaaaaaaaaaaaaaaaaa&info_hash=bbbbbbbbbbbbbbbbbbbb", hashes, 2, &count); assert(rc == TRACKER_OK); assert(count == 2); assert(memcmp(hashes[0], "aaaaaaaaaaaaaaaaaaaa", 20) == 0); assert(memcmp(hashes[1], "bbbbbbbbbbbbbbbbbbbb", 20) == 0); memset(files, 0, sizeof(files)); memcpy(files[0].info_hash, hashes[0], 20); files[0].complete = 11; files[0].downloaded = 22; files[0].incomplete = 33; resp.files = files; resp.file_count = 1; assert(tracker_http_write_scrape_response(&resp, buf, sizeof(buf), &written) == TRACKER_OK); assert(memmem(buf, written, "5:filesd20:aaaaaaaaaaaaaaaaaaaa", 31) != NULL); assert(memmem(buf, written, "8:completei11e", 14) != NULL); } static void test_http_client_helpers(void) { tracker_announce_request req; tracker_announce_request parsed; tracker_announce_response resp; tracker_announce_response parsed_resp; tracker_scrape_response scrape; tracker_scrape_response parsed_scrape; tracker_scrape_file files[1]; tracker_scrape_file parsed_files[2]; tracker_peer peers[2]; tracker_peer parsed_peers[4]; uint8_t buf[512]; char query[512]; size_t written = 0; uint8_t hashes[2][20]; size_t hash_count = 0; fill_announce(&req, "abcdefghijklmnopqrst", "-TC0001-abcdefghijkl", 6881, 12345, TRACKER_EVENT_STARTED); req.uploaded = 10; req.downloaded = 20; req.numwant = 25; assert(tracker_http_write_announce_query(&req, query, sizeof(query), &written) == TRACKER_OK); assert(written > 0); assert(tracker_http_parse_announce_query(query, &parsed) == TRACKER_OK); assert(memcmp(parsed.info_hash, req.info_hash, 20) == 0); assert(memcmp(parsed.peer_id, req.peer_id, 20) == 0); assert(parsed.port == 6881); assert(parsed.left == 12345); assert(parsed.event == TRACKER_EVENT_STARTED); assert(parsed.numwant == 25); memset(peers, 0, sizeof(peers)); peers[0].family = TRACKER_ADDR_IPV4; peers[0].addr[0] = 1; peers[0].addr[1] = 2; peers[0].addr[2] = 3; peers[0].addr[3] = 4; peers[0].port = 6000; peers[1].family = TRACKER_ADDR_IPV6; peers[1].addr[15] = 1; peers[1].port = 6001; memset(&resp, 0, sizeof(resp)); resp.interval = 1800; resp.min_interval = 60; resp.complete = 3; resp.incomplete = 4; resp.peers = peers; resp.peer_count = 2; resp.compact = 1; assert(tracker_http_write_announce_response(&resp, buf, sizeof(buf), &written) == TRACKER_OK); assert(tracker_http_parse_announce_response(buf, written, parsed_peers, 4, &parsed_resp) == TRACKER_OK); assert(parsed_resp.interval == 1800); assert(parsed_resp.min_interval == 60); assert(parsed_resp.complete == 3); assert(parsed_resp.incomplete == 4); assert(parsed_resp.peer_count == 2); assert(parsed_peers[0].family == TRACKER_ADDR_IPV4); assert(parsed_peers[0].port == 6000); assert(parsed_peers[1].family == TRACKER_ADDR_IPV6); assert(parsed_peers[1].port == 6001); memcpy(hashes[0], "aaaaaaaaaaaaaaaaaaaa", 20); memcpy(hashes[1], "bbbbbbbbbbbbbbbbbbbb", 20); assert(tracker_http_write_scrape_query(hashes, 2, query, sizeof(query), &written) == TRACKER_OK); assert(tracker_http_parse_scrape_query(query, hashes, 2, &hash_count) == TRACKER_OK); assert(hash_count == 2); memset(files, 0, sizeof(files)); memcpy(files[0].info_hash, "aaaaaaaaaaaaaaaaaaaa", 20); files[0].complete = 9; files[0].downloaded = 8; files[0].incomplete = 7; scrape.files = files; scrape.file_count = 1; assert(tracker_http_write_scrape_response(&scrape, buf, sizeof(buf), &written) == TRACKER_OK); assert(tracker_http_parse_scrape_response(buf, written, parsed_files, 2, &parsed_scrape) == TRACKER_OK); assert(parsed_scrape.file_count == 1); assert(memcmp(parsed_files[0].info_hash, files[0].info_hash, 20) == 0); assert(parsed_files[0].complete == 9); assert(parsed_files[0].downloaded == 8); assert(parsed_files[0].incomplete == 7); } static void test_udp_announce_parse(void) { uint8_t pkt[128]; tracker_udp_request req; memset(pkt, 0, sizeof(pkt)); put64(pkt, 0x0102030405060708ULL); put32(pkt + 8, TRACKER_UDP_ANNOUNCE); put32(pkt + 12, 0x11223344); memcpy(pkt + 16, "aaaaaaaaaaaaaaaaaaaa", 20); memcpy(pkt + 36, "bbbbbbbbbbbbbbbbbbbb", 20); put64(pkt + 56, 100); put64(pkt + 64, 200); put64(pkt + 72, 300); put32(pkt + 80, TRACKER_EVENT_COMPLETED); put32(pkt + 88, 0xaabbccdd); put32(pkt + 92, 25); pkt[96] = 0x1a; pkt[97] = 0xe1; pkt[98] = 0x02; pkt[99] = 12; memcpy(pkt + 100, "/dir?a=b&c=d", 12); pkt[112] = 0x00; assert(tracker_udp_parse_request(pkt, 113, TRACKER_ADDR_IPV4, &req) == TRACKER_OK); assert(req.action == TRACKER_UDP_ANNOUNCE); assert(req.transaction_id == 0x11223344); assert(req.connection_id == 0x0102030405060708ULL); assert(memcmp(req.announce.info_hash, "aaaaaaaaaaaaaaaaaaaa", 20) == 0); assert(memcmp(req.announce.peer_id, "bbbbbbbbbbbbbbbbbbbb", 20) == 0); assert(req.announce.downloaded == 100); assert(req.announce.left == 200); assert(req.announce.uploaded == 300); assert(req.announce.event == TRACKER_EVENT_COMPLETED); assert(req.announce.key == 0xaabbccdd); assert(req.announce.numwant == 25); assert(req.announce.port == 6881); assert(strcmp(req.announce.url_data, "/dir?a=b&c=d") == 0); } static void test_udp_responses(void) { uint8_t buf[256]; size_t written = 0; tracker_peer peer; tracker_announce_response announce; tracker_scrape_file file; tracker_scrape_response scrape; assert(tracker_udp_write_connect_response(0x1234, 0x0102030405060708ULL, buf, sizeof(buf), &written) == TRACKER_OK); assert(written == 16); assert(get32(buf) == TRACKER_UDP_CONNECT); assert(get32(buf + 4) == 0x1234); memset(&peer, 0, sizeof(peer)); peer.family = TRACKER_ADDR_IPV4; peer.addr[0] = 10; peer.addr[3] = 5; peer.port = 6000; memset(&announce, 0, sizeof(announce)); announce.interval = 900; announce.complete = 2; announce.incomplete = 4; announce.peers = &peer; announce.peer_count = 1; assert(tracker_udp_write_announce_response(0x99, TRACKER_ADDR_IPV4, &announce, buf, sizeof(buf), &written) == TRACKER_OK); assert(written == 26); assert(get32(buf) == TRACKER_UDP_ANNOUNCE); assert(get32(buf + 8) == 900); assert(get32(buf + 12) == 4); assert(get32(buf + 16) == 2); assert(buf[20] == 10 && buf[23] == 5); memset(&file, 0, sizeof(file)); file.complete = 8; file.downloaded = 9; file.incomplete = 10; scrape.files = &file; scrape.file_count = 1; assert(tracker_udp_write_scrape_response(0x77, &scrape, buf, sizeof(buf), &written) == TRACKER_OK); assert(written == 20); assert(get32(buf) == TRACKER_UDP_SCRAPE); assert(get32(buf + 8) == 8); assert(get32(buf + 12) == 9); assert(get32(buf + 16) == 10); } static void test_udp_client_helpers(void) { uint8_t buf[512]; uint8_t response_buf[512]; size_t written = 0; size_t response_written = 0; tracker_udp_request parsed_req; tracker_announce_request req; tracker_announce_response resp; tracker_announce_response parsed_resp; tracker_scrape_response scrape; tracker_scrape_response parsed_scrape; tracker_scrape_file file; tracker_scrape_file parsed_files[2]; tracker_peer peer; tracker_peer parsed_peers[2]; uint8_t hashes[1][20]; uint64_t connection_id = 0; assert(tracker_udp_write_connect_request(0x5555, buf, sizeof(buf), &written) == TRACKER_OK); assert(tracker_udp_parse_request(buf, written, TRACKER_ADDR_IPV4, &parsed_req) == TRACKER_OK); assert(parsed_req.action == TRACKER_UDP_CONNECT); assert(parsed_req.transaction_id == 0x5555); assert(tracker_udp_write_connect_response(0x5555, 0x0102030405060708ULL, response_buf, sizeof(response_buf), &response_written) == TRACKER_OK); assert(tracker_udp_parse_connect_response(response_buf, response_written, 0x5555, &connection_id) == TRACKER_OK); assert(connection_id == 0x0102030405060708ULL); fill_announce(&req, "abcdefghijklmnopqrst", "-UC0001-abcdefghijkl", 7000, 42, TRACKER_EVENT_STARTED); req.downloaded = 5; req.uploaded = 6; req.numwant = 10; strcpy(req.url_data, "/announce?token=abc"); assert(tracker_udp_write_announce_request(connection_id, 0x6666, &req, buf, sizeof(buf), &written) == TRACKER_OK); assert(tracker_udp_parse_request(buf, written, TRACKER_ADDR_IPV4, &parsed_req) == TRACKER_OK); assert(parsed_req.action == TRACKER_UDP_ANNOUNCE); assert(parsed_req.transaction_id == 0x6666); assert(parsed_req.connection_id == connection_id); assert(parsed_req.announce.port == 7000); assert(parsed_req.announce.left == 42); assert(strcmp(parsed_req.announce.url_data, "/announce?token=abc") == 0); memset(&peer, 0, sizeof(peer)); peer.family = TRACKER_ADDR_IPV4; peer.addr[0] = 8; peer.addr[1] = 8; peer.addr[2] = 4; peer.addr[3] = 4; peer.port = 51413; memset(&resp, 0, sizeof(resp)); resp.interval = 900; resp.complete = 11; resp.incomplete = 12; resp.peers = &peer; resp.peer_count = 1; assert(tracker_udp_write_announce_response(0x6666, TRACKER_ADDR_IPV4, &resp, response_buf, sizeof(response_buf), &response_written) == TRACKER_OK); assert(tracker_udp_parse_announce_response(response_buf, response_written, 0x6666, TRACKER_ADDR_IPV4, parsed_peers, 2, &parsed_resp) == TRACKER_OK); assert(parsed_resp.interval == 900); assert(parsed_resp.complete == 11); assert(parsed_resp.incomplete == 12); assert(parsed_resp.peer_count == 1); assert(parsed_peers[0].addr[0] == 8); assert(parsed_peers[0].port == 51413); memcpy(hashes[0], "aaaaaaaaaaaaaaaaaaaa", 20); assert(tracker_udp_write_scrape_request(connection_id, 0x7777, hashes, 1, buf, sizeof(buf), &written) == TRACKER_OK); assert(tracker_udp_parse_request(buf, written, TRACKER_ADDR_IPV4, &parsed_req) == TRACKER_OK); assert(parsed_req.action == TRACKER_UDP_SCRAPE); assert(parsed_req.scrape_count == 1); assert(memcmp(parsed_req.scrape_hashes[0], hashes[0], 20) == 0); memset(&file, 0, sizeof(file)); file.complete = 1; file.downloaded = 2; file.incomplete = 3; scrape.files = &file; scrape.file_count = 1; assert(tracker_udp_write_scrape_response(0x7777, &scrape, response_buf, sizeof(response_buf), &response_written) == TRACKER_OK); assert(tracker_udp_parse_scrape_response(response_buf, response_written, 0x7777, parsed_files, 2, &parsed_scrape) == TRACKER_OK); assert(parsed_scrape.file_count == 1); assert(parsed_files[0].complete == 1); assert(parsed_files[0].downloaded == 2); assert(parsed_files[0].incomplete == 3); } static void test_store_announce_scrape_stop_and_prune(void) { tracker_store_config cfg; tracker_store *store; tracker_announce_request req1; tracker_announce_request req2; tracker_announce_response resp; tracker_scrape_response scrape; tracker_scrape_file files[1]; tracker_peer source1 = ipv4_source(10, 0, 0, 1); tracker_peer source2 = ipv4_source(10, 0, 0, 2); tracker_peer out[8]; uint8_t hashes[1][20]; memset(&cfg, 0, sizeof(cfg)); cfg.interval = 1200; cfg.min_interval = 60; cfg.peer_timeout = 10; cfg.default_numwant = 50; cfg.max_numwant = 50; cfg.random_seed = 1; store = tracker_store_create(&cfg); assert(store != NULL); fill_announce(&req1, "aaaaaaaaaaaaaaaaaaaa", "peer-000000000000001", 6001, 100, TRACKER_EVENT_STARTED); assert(tracker_store_announce(store, &req1, &source1, 100, out, 8, &resp) == TRACKER_OK); assert(resp.interval == 1200); assert(resp.min_interval == 60); assert(resp.complete == 0); assert(resp.incomplete == 1); assert(resp.peer_count == 0); assert(tracker_store_peer_count(store) == 1); fill_announce(&req2, "aaaaaaaaaaaaaaaaaaaa", "peer-000000000000002", 6002, 0, TRACKER_EVENT_STARTED); assert(tracker_store_announce(store, &req2, &source2, 101, out, 8, &resp) == TRACKER_OK); assert(resp.complete == 1); assert(resp.incomplete == 1); assert(resp.peer_count == 1); assert(out[0].port == 6001); assert(out[0].addr[3] == 1); req1.left = 0; req1.event = TRACKER_EVENT_COMPLETED; assert(tracker_store_announce(store, &req1, &source1, 102, out, 8, &resp) == TRACKER_OK); assert(resp.complete == 2); assert(resp.incomplete == 0); assert(resp.peer_count == 1); assert(out[0].port == 6002); memcpy(hashes[0], "aaaaaaaaaaaaaaaaaaaa", 20); assert(tracker_store_scrape(store, hashes, 1, files, 1, &scrape) == TRACKER_OK); assert(scrape.file_count == 1); assert(files[0].complete == 2); assert(files[0].incomplete == 0); assert(files[0].downloaded == 1); req2.event = TRACKER_EVENT_STOPPED; assert(tracker_store_announce(store, &req2, &source2, 103, out, 8, &resp) == TRACKER_OK); assert(resp.complete == 1); assert(resp.incomplete == 0); assert(resp.peer_count == 0); assert(tracker_store_peer_count(store) == 1); assert(tracker_store_prune(store, 200) == 1); assert(tracker_store_peer_count(store) == 0); assert(tracker_store_scrape(store, hashes, 1, files, 1, &scrape) == TRACKER_OK); assert(files[0].complete == 0); assert(files[0].incomplete == 0); assert(files[0].downloaded == 1); tracker_store_destroy(store); } int main(void) { test_http_announce_parse(); test_http_compact_response(); test_http_scrape(); test_http_client_helpers(); test_dht_queries(); test_dht_responses(); test_dht_error(); test_udp_announce_parse(); test_udp_responses(); test_udp_client_helpers(); test_store_announce_scrape_stop_and_prune(); puts("tracker protocol tests passed"); return 0; }