ssize_t bencode_dict_end(uint8_t *output, size_t output_size) {
if(NULL==output) { return -1; }
- if(output_size<=1) { return -1; }
+ if(output_size<1) { return -1; }
output[0] = 'e';
ssize_t bencode_dict_start(uint8_t *output, size_t output_size) {
if(NULL==output) { return -1; }
- if(output_size<=1) { return -1; }
+ if(output_size<1) { return -1; }
output[0] = 'd';
#include<torrent.h>
-static size_t torrent_file_info_length(struct tree *tree);
+static size_t torrent_file_info_length(struct torrent*);
static uint8_t file_tree_string[] = "file tree";
static uint8_t meta_version_string[] = "meta version";
+
+#define TORRENT_FILE_META_VERSION 2
+
static uint8_t name_string[] = "name";
static uint8_t piece_length_string[] = "piece length";
if(NULL==buf) { return -1; }
- buf_len = torrent_file_info_length(torrent_p->tree);
+ buf_len = torrent_file_info_length(torrent_p);
p = malloc(sizeof(uint8_t)*buf_len);
if(NULL==p) { return -1; }
if((i = bencode_string(meta_version_string,sizeof(meta_version_string)-1,&(p[len]),buf_len-len))<0) { goto clean; }
len += i;
- if((i = bencode_int(2,&(p[len]),buf_len-len))<0) { goto clean; }
+ if((i = bencode_int(TORRENT_FILE_META_VERSION,&(p[len]),buf_len-len))<0) { goto clean; }
len += i;
if((i = bencode_string(name_string,sizeof(name_string)-1,&(p[len]),buf_len-len))<0) { goto clean; }
if((i = bencode_int(torrent_p->piece_length,&(p[len]),buf_len-len))<0) { goto clean; }
len += i;
+ if((i = bencode_dict_end(&(p[len]),buf_len-len))<0) { goto clean; }
+ len += i;
+
+ (*buf) = p;
+
return len;
clean:
free(p);
return -1;
}
-static size_t torrent_file_info_length(struct tree *tree) {
- size_t i;
+static size_t torrent_file_info_length(struct torrent *p) {
+ size_t i, len;
- i = 0;
+ i = 2; // opening '{' (d) and ending '}' (e)
// string length = sizeof()-1, +1 for ':' included
i += sizeof(file_tree_string)+bencode_size_int(sizeof(file_tree_string));
- i += sizeof(meta_version_string)+bencode_size_int(sizeof(file_tree_string));
- i += sizeof(name_string)+bencode_size_int(sizeof(file_tree_string));
- i += sizeof(piece_length_string)+bencode_size_int(sizeof(file_tree_string));
+ i += tree_bencode_length(p->tree);
+
+ i += sizeof(meta_version_string)+bencode_size_int(sizeof(meta_version_string));
+ i += bencode_size_int(TORRENT_FILE_META_VERSION)+2; // i[INT]e
+
+ len = strlen(p->name);
+ i += sizeof(name_string)+bencode_size_int(sizeof(name_string));
+ i += bencode_size_int(len)+len;
- i += tree_bencode_length(tree);
+ i += sizeof(piece_length_string)+bencode_size_int(sizeof(piece_length_string));
+ i += bencode_size_int(p->piece_length)+2; // i[INT]e
return i;
}
info = NULL;
if((i = torrent_file_info(torrent_p,&info))<0) { goto clean; }
-
if(hash(info,i,infohash,crypto_hash_sha256_BYTES)<0) { goto clean; }
free(info);
info = NULL;
}
hashes = malloc(sizeof(unsigned char*));
- if(NULL==hashes) {
- return -1;
- }
+ if(NULL==hashes) { return -1; }
index = 0;
for(size_t i=0;i<p->files.roots->size;i++) {
file_p = (struct file*)p->files.roots->map[i];
if(file_p!=NULL) {
hashes[index] = file_p->root;
+ index++;
}
}
qsort(hashes,pieces,sizeof(unsigned char*),&piece_layer_sort);
- // hashes[0] should never be NULL
- if(NULL==hashes[0]) { return -1; }
-
- file_p = hashmap_find(p->files.roots,hashes[0],crypto_hash_sha256_BYTES);
- if(NULL==file_p) { return -1; }
-
for(size_t i=0;i<pieces;i++) {
- file_p = hashmap_find(p->files.roots,hash,crypto_hash_sha256_BYTES);
- if(NULL==file_p) { break; } // sorting guarantees all NULLs at end
+ file_p = hashmap_find(p->files.roots,hashes[i],crypto_hash_sha256_BYTES);
+ if(NULL==file_p) { goto clean; }
if(torrent_bencode_piece_layers(fp,file_p)<0) { goto clean; }
}
if(NULL==p1) { return 1; }
if(NULL==p2) { return -1; }
- return memcmp(p1,p2,crypto_hash_sha256_BYTES);
+ return memcmp(*(unsigned char**)p1,*(unsigned char**)p2,crypto_hash_sha256_BYTES);
}
#define TEST_FILE_4 PREFIX "/.test.meta"
#define TEST_FILE_4_CONTENTS ";alsikdjf;lkasdjflk\n;asjdflk\n;ajsdklfjl;aksdfjla;kj"
#define TEST_FILE_5 PREFIX "/random.test"
+#define TEST_FILE_6 PREFIX "/file.torrent"
void clean_env();
void reset_env();
static void torrent_add_basic_test();
static void torrent_file_info_basic_test();
static void torrent_file_path_basic_test();
+static void torrent_file_piece_layers_basic_test();
static void torrent_init_basic_test();
static void torrent_magnet_basic_test();
static void torrent_setup_example(struct torrent**);
torrent_init_basic_test();
torrent_add_basic_test();
+ torrent_file_piece_layers_basic_test();
torrent_magnet_basic_test();
torrent_file_info_basic_test();
torrent_file_path_basic_test();
assert(-1==torrent_file_info(NULL,NULL));
assert(-1==torrent_file_info(torrent,NULL));
- assert(212==torrent_file_info(torrent,&buf));
+ assert(213==torrent_file_info(torrent,&buf));
- uint8_t expected[] = "d9:file treed4:testd0:d6:lengthi0e11:pieces root32:" "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" "ee5:test2d0:d6:lengthi0e11:pieces root32:" "\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02" "eee12:meta versioni2e4:name5:.test12:piece lengthi16384e";
- assert(memcmp(buf,expected,212)==0);
+ uint8_t expected[] = "d9:file treed4:testd0:d6:lengthi0e11:pieces root32:" "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" "ee5:test2d0:d6:lengthi0e11:pieces root32:" "\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02" "eee12:meta versioni2e4:name5:.test12:piece lengthi16384ee";
+ assert(memcmp(buf,expected,213)==0);
free(buf);
free(p);
}
+static void hash_torrent_file(unsigned char *hash, size_t hash_len) {
+ uint8_t buf[16384];
+ crypto_hash_sha256_state st;
+ FILE *fp;
+ size_t i;
+
+ assert(hash_len==crypto_hash_sha256_BYTES);
+
+ fp = fopen(TEST_FILE_6,"w");
+ assert(fp!=NULL);
+
+ assert(1==hash_init(&st));
+
+ while(feof(fp)!=0) {
+ i = fread(buf,sizeof(uint8_t),16384,fp);
+ if(i>0) {
+ assert(1==hash_update(&st,buf,i));
+ }
+ }
+
+ assert(0==fclose(fp));
+
+ assert(hash_final(&st,hash,crypto_hash_sha256_BYTES)==1);
+}
+
+static void torrent_file_piece_layers_basic_test() {
+ struct torrent *torrent;
+ FILE *fp;
+ unsigned char hash[crypto_hash_sha256_BYTES];
+ unsigned char expected[crypto_hash_sha256_BYTES] = {227,176,196,66,152,252,28,20,154,251,244,200,153,111,185,36,39,174,65,228,100,155,147,76,164,149,153,27,120,82,184,85};
+
+ fp = fopen(TEST_FILE_6,"w");
+ assert(fp!=NULL);
+
+ torrent_setup_example(&torrent);
+ assert(torrent_file_piece_layers(fp,torrent)==1);
+
+ assert(0==fclose(fp));
+
+ hash_torrent_file(hash,crypto_hash_sha256_BYTES);
+
+ assert(memcmp(hash,expected,crypto_hash_sha256_BYTES)==0);
+
+ torrent_free(torrent);
+
+ reset_env();
+}
+
static void torrent_init_basic_test() {
struct torrent *torrent;
static void torrent_magnet_basic_test() {
struct torrent *torrent;
char *p;
+ char expected[] = "magnet:?xt=urn:btmh:59b2020fe4275cac5c3b8ac32bdc79010c95cf0bac2fd91ced8dd071f8ef91ca&dn=" TEST_DIRECTORY;
torrent_setup_example(&torrent);
p = torrent_magnet(torrent);
assert(p!=NULL);
- assert(strcmp(p,"magnet:?xt=urn:btmh:d2cb0c8d48b492e0407e2b24ae6b9c2e542d9addf08d71eef8db7008944def9e&dn=" TEST_DIRECTORY)==0);
+ assert(strcmp(p,expected)==0);
free(p);
torrent_free(torrent);