#include "naut/tracker.h" #include "naut/bencode.h" #include "test.h" #include int main(void) { naut_announce_req req; memset(&req, 0, sizeof req); for (int i = 0; i < 20; i++) { req.info_hash[i] = (uint8_t)i; req.peer_id[i] = (uint8_t)(0x80 + i); } req.port = 6881; req.left = 1000; req.numwant = -1; req.key = 0xdeadbeef; req.event = NAUT_TEV_STARTED; /* --- HTTP announce URL --- */ char url[1024]; size_t n = naut_tracker_http_url("http://t.example/announce", &req, url, sizeof url); CHECK(n > 0); CHECK(strstr(url, "info_hash=%00%01%02") != NULL); /* binary pct-encoded */ CHECK(strstr(url, "port=6881") != NULL); CHECK(strstr(url, "compact=1") != NULL); CHECK(strstr(url, "event=started") != NULL); /* base already having a query uses '&' */ naut_tracker_http_url("http://t.example/announce?x=1", &req, url, sizeof url); CHECK(strstr(url, "announce?x=1&info_hash=") != NULL); req.event = (naut_tracker_event)99; CHECK(naut_tracker_http_url("http://t.example/announce", &req, url, sizeof url) == 0); req.event = NAUT_TEV_STARTED; /* --- HTTP response parse: compact peers --- */ { /* d8:intervali1800e5:peers12:e */ uint8_t body[128]; size_t b = 0; const char *pre = "d8:intervali1800e8:completei5e10:incompletei2e5:peers12:"; memcpy(body, pre, strlen(pre)); b = strlen(pre); uint8_t peers[12] = { 1,2,3,4, 0x1a,0xe1, 10,0,0,1, 0x1a,0xe2 }; memcpy(body + b, peers, 12); b += 12; body[b++] = 'e'; naut_tracker_response r; CHECK(naut_tracker_parse_http(body, b, &r) == NAUT_OK); CHECK_EQ(r.interval, 1800); CHECK_EQ(r.seeders, 5); CHECK_EQ(r.leechers, 2); CHECK_EQ(r.num_peers, 2); CHECK(r.peers[0].ip[0]==1 && r.peers[0].ip[3]==4 && r.peers[0].port==0x1ae1); CHECK(r.peers[1].ip[0]==10 && r.peers[1].port==0x1ae2); naut_tracker_response_free(&r); } /* --- failure reason --- */ { const char *body = "d14:failure reason17:torrent not founde"; naut_tracker_response r; CHECK(naut_tracker_parse_http((const uint8_t *)body, strlen(body), &r) == NAUT_ERR_PROTO); CHECK(r.failure && strcmp(r.failure, "torrent not found") == 0); naut_tracker_response_free(&r); } /* --- UDP connect codec --- */ { uint8_t pkt[98]; naut_udp_build_connect(pkt, 0x11223344); /* protocol id 0x41727101980, action 0, txid */ CHECK(pkt[0]==0 && pkt[1]==0 && pkt[2]==0x04 && pkt[3]==0x17 && pkt[4]==0x27 && pkt[5]==0x10 && pkt[6]==0x19 && pkt[7]==0x80); CHECK(pkt[8]==0 && pkt[11]==0); /* action connect */ CHECK(pkt[12]==0x11 && pkt[15]==0x44); /* txid */ /* build a fake connect response and parse it */ uint8_t resp[16] = {0}; resp[3] = 0; /* action connect */ resp[4]=0x11; resp[5]=0x22; resp[6]=0x33; resp[7]=0x44; /* txid */ for (int i = 0; i < 8; i++) resp[8+i] = (uint8_t)(0xA0 + i); /* conn id */ uint64_t cid = 0; CHECK(naut_udp_parse_connect(resp, 16, 0x11223344, &cid) == NAUT_OK); CHECK(cid == 0xA0A1A2A3A4A5A6A7ULL); CHECK(naut_udp_parse_connect(resp, 16, 0x99999999, &cid) == NAUT_ERR_PROTO); /* wrong txid */ } /* --- UDP announce codec round-trip --- */ { uint8_t pkt[98]; naut_udp_build_announce(pkt, 0xA0A1A2A3A4A5A6A7ULL, 0x55667788, &req); CHECK(pkt[11] == 1); /* action announce */ CHECK(memcmp(pkt + 16, req.info_hash, 20) == 0); CHECK(memcmp(pkt + 36, req.peer_id, 20) == 0); CHECK(pkt[83] == NAUT_TEV_STARTED); /* event low byte */ CHECK((pkt[96]<<8 | pkt[97]) == 6881); /* port */ /* fake announce response: action=1, txid, interval, leech, seed, 1 peer */ uint8_t resp[26] = {0}; resp[3] = 1; resp[4]=0x55; resp[5]=0x66; resp[6]=0x77; resp[7]=0x88; resp[11] = 0x84; /* interval 0x84 = 132 */ resp[15] = 3; /* leechers */ resp[19] = 7; /* seeders */ resp[20]=192; resp[21]=168; resp[22]=0; resp[23]=5; resp[24]=0x1a; resp[25]=0xe1; naut_tracker_response r; CHECK(naut_udp_parse_announce(resp, 26, 0x55667788, &r) == NAUT_OK); CHECK_EQ(r.interval, 132); CHECK_EQ(r.leechers, 3); CHECK_EQ(r.seeders, 7); CHECK_EQ(r.num_peers, 1); CHECK(r.peers[0].ip[0]==192 && r.peers[0].ip[3]==5 && r.peers[0].port==0x1ae1); naut_tracker_response_free(&r); uint8_t malformed[27]; memcpy(malformed, resp, sizeof resp); malformed[26] = 0; CHECK(naut_udp_parse_announce(malformed, sizeof malformed, 0x55667788, &r) == NAUT_ERR_PROTO); } TEST_MAIN_END(); }