]> infiniteadaptability.org Git - seeder/commitdiff
...
authoralex <[email protected]>
Wed, 27 Oct 2021 21:18:38 +0000 (14:18 -0700)
committeralex <[email protected]>
Wed, 27 Oct 2021 21:18:38 +0000 (14:18 -0700)
Makefile.am
inc/bencode.h [new file with mode: 0644]
src/bencode/decode.c [new file with mode: 0644]
src/bencode/encode.c [new file with mode: 0644]
test/unit/Makefile.am
test/unit/bencode.tests.c [new file with mode: 0644]
test/unit/torrent.tests.c

index 0b37448019f13cd0f491cf433d5cecf233d5e62e..90c8c4edebdc19b1eb03e84b129ed68c5cfe3926 100644 (file)
@@ -13,6 +13,8 @@ bin_PROGRAMS = seederd
 
 seederd_SOURCES = \
        src/add.c \
+       src/bencode/decode.c \
+       src/bencode/encode.c \
        src/default.c \
        src/file.c \
        src/hash.c \
@@ -44,6 +46,7 @@ seederd_SOURCES = \
 
 seederd_SOURCES += \
        inc/add.h \
+       inc/bencode.h \
        inc/default.h \
        inc/file.h \
        inc/hash.h \
diff --git a/inc/bencode.h b/inc/bencode.h
new file mode 100644 (file)
index 0000000..190613e
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __BENCODE_H_
+#define __BENCODE_H_
+
+#include<stddef.h>
+#include<stdint.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+
+enum bencode_type {
+       BENCODE_DICTIONARY,
+       BENCODE_INTEGER,
+       BENCODE_LIST,
+       BENCODE_STRING
+};
+
+ssize_t bdecode_integer(const uint8_t*,size_t,long long int*);
+ssize_t bdecode_string(const uint8_t*,size_t,uint8_t*,size_t);
+enum bencode_type bdecode_type(const uint8_t*,size_t);
+ssize_t bencode_dict_end(uint8_t*,size_t);
+ssize_t bencode_dict_start(uint8_t*,size_t);
+ssize_t bencode_int(int,uint8_t*,size_t);
+ssize_t bencode_list_end(uint8_t*,size_t);
+ssize_t bencode_list_start(uint8_t*,size_t);
+ssize_t bencode_string(const uint8_t*,size_t,uint8_t*,size_t);
+
+#endif
diff --git a/src/bencode/decode.c b/src/bencode/decode.c
new file mode 100644 (file)
index 0000000..23c7d21
--- /dev/null
@@ -0,0 +1,67 @@
+#include<bencode.h>
+
+ssize_t bdecode_integer(const uint8_t *buf, size_t buf_len, long long int *output) {
+       if(NULL==buf) { return -1; }
+       if(buf_len<=0) { return -1; }
+       if(NULL==output) { return -1; }
+
+       const uint8_t *p = NULL;
+       for(size_t i=0;i<buf_len;i++) {
+               // 0 padded integers are invalid
+               if((1==i)&&(buf[i]=='0')&&(buf_len>3)) { return -1; }
+               if(buf[i]=='e') {
+                       p = &(buf[i]);
+               }
+       }
+
+       if(NULL==p) { return -1; }
+
+       ssize_t len = p - (buf+1);
+       uint8_t *num_string = (uint8_t*) strndup((const char*)&(buf[1]),len);
+       *output = atoll((char *)num_string);
+       free(num_string);
+
+       len += 2;
+
+       return len;
+}
+
+ssize_t bdecode_string(const uint8_t *buf, size_t buf_len, uint8_t *output, size_t output_size) {
+       if(NULL==buf) { return -1; }
+       if(buf_len<=0) { return -1; }
+       if(NULL==output) { return -1; }
+
+       const uint8_t *p = NULL;
+       for(size_t i=0;i<buf_len;i++) {
+               if(buf[i]==':') {
+                       p = &(buf[i]);
+                       break;
+               }
+       }
+
+       if(NULL==p) { return -1; }
+       uint8_t *num_string = (uint8_t*) strndup((const char*)buf,p-buf);
+       int str_len = atoi((char *)num_string);
+       ssize_t len = str_len;
+       free(num_string);
+
+       if((str_len<=0)||(len>output_size)) { return -1; }
+
+       p++;
+       memcpy(output,p,str_len);
+
+       return len;
+}
+
+enum bencode_type bdecode_type(const uint8_t *buf, size_t len) {
+       switch(buf[0]) {
+               case 'i':
+                       return BENCODE_INTEGER;
+               case 'l':
+                       return BENCODE_LIST;
+               case 'd':
+                       return BENCODE_DICTIONARY;
+               default:
+                       return BENCODE_STRING;
+       }
+}
diff --git a/src/bencode/encode.c b/src/bencode/encode.c
new file mode 100644 (file)
index 0000000..b21c6b8
--- /dev/null
@@ -0,0 +1,85 @@
+#include<bencode.h>
+
+static size_t size_int(int i);
+
+ssize_t bencode_dict_end(uint8_t *output, size_t output_size) {
+       if(NULL==output) { return -1; }
+       if(output_size<=1) { return -1; }
+
+       output[0] = 'e';
+
+       return 1;
+}
+
+ssize_t bencode_dict_start(uint8_t *output, size_t output_size) {
+       if(NULL==output) { return -1; }
+       if(output_size<=1) { return -1; }
+
+       output[0] = 'd';
+
+       return 1;
+}
+
+ssize_t bencode_int(int to_encode, uint8_t *output, size_t output_size) {
+       size_t i;
+       int ret;
+
+       if(NULL==output) { return -1; }
+
+       i = size_int(to_encode);
+       i += 2;
+
+       if((ret = snprintf((char*)output,output_size,"i%de",to_encode))<0) { return -1; }
+       if(ret!=i) { return -1; }
+
+       return i;
+}
+
+ssize_t bencode_list_end(uint8_t *output, size_t output_size) {
+       if(NULL==output) { return -1; }
+       if(output_size<=1) { return -1; }
+
+       output[0] = 'e';
+
+       return 1;
+}
+
+ssize_t bencode_list_start(uint8_t *output, size_t output_size) {
+       if(NULL==output) { return -1; }
+       if(output_size<=1) { return -1; }
+
+       output[0] = 'l';
+
+       return 1;
+}
+
+ssize_t bencode_string(const uint8_t *str, size_t len, uint8_t *output, size_t output_size) {
+       size_t i;
+       int ret;
+       
+       if(NULL==str) { return -1; }
+       if(len<=0) { return -1; }
+       if(NULL==output) { return -1; }
+       if(len>output_size) { return -1; }
+
+       i = size_int(len);
+       i++;
+       i += len;
+
+       if((ret = snprintf((char*)output,output_size,"%lu:%s",len,(const char*)str))<0) { return -1; }
+
+       if(ret!=i) { return -1; }
+
+       return i;
+}
+
+
+static size_t size_int(int i) {
+       i = abs(i);
+       size_t j = 0;
+       while(i>0) {
+               i /= 10;
+               j++;
+       }
+       return j;
+}
index 41d1d2daefc4f75e22dac7c35c3965fe8fdb4361..77aa90a0eff92f7ba30fe64c63fd3adb0d08b5b4 100644 (file)
@@ -12,7 +12,7 @@ AM_CPPFLAGS += \
        -DNDEBUG
 endif
 
-check_PROGRAMS = file.tests hash.tests hashmap.tests torrent.tests tree.tests util.filter.tests 
+check_PROGRAMS = bencode.tests file.tests hash.tests hashmap.tests torrent.tests tree.tests util.filter.tests 
 TESTS = $(check_PROGRAMS)
 
 if ENABLE_MEMCHECK
@@ -22,6 +22,12 @@ endif
 
 common_SOURCES = test_utils.c
 
+bencode_tests_SOURCES = \
+       $(common_SOURCES) \
+       bencode.tests.c \
+       $(top_srcdir)/src/bencode/decode.c \
+       $(top_srcdir)/src/bencode/encode.c
+
 file_tests_SOURCES = \
        $(common_SOURCES) \
        file.tests.c \
diff --git a/test/unit/bencode.tests.c b/test/unit/bencode.tests.c
new file mode 100644 (file)
index 0000000..08e1cad
--- /dev/null
@@ -0,0 +1,150 @@
+#include<test_utils.h>
+
+#include<bencode.h>
+
+int main();
+static void bdecode_integer_basic_test();
+static void bdecode_string_basic_test();
+static void bdecode_type_basic_test();
+static void bencode_dict_basic_test();
+static void bencode_list_basic_test();
+static void bencode_string_basic_test();
+
+int main() {
+       setup_env();
+       
+       bdecode_integer_basic_test();
+       bdecode_string_basic_test();
+       bdecode_type_basic_test();
+       bencode_dict_basic_test();
+       bencode_list_basic_test();
+       bencode_string_basic_test();
+
+       clean_env();
+
+       return EXIT_SUCCESS;
+}
+
+static void bdecode_integer_basic_test() {
+       uint8_t str1[] = "i10e";
+       uint8_t str2[] = "i0e";
+       uint8_t str3[] = "i0023423e";
+       uint8_t str4[] = "i10928390128301e";
+       long long int i;
+
+       assert(bdecode_integer(NULL,sizeof(str1)-1,&i)==-1);
+       assert(bdecode_integer(str1,0,&i)==-1);
+       assert(bdecode_integer(str1,sizeof(str1)-1,NULL)==-1);
+       assert(bdecode_integer(str1,sizeof(str1)-1,&i)==4);
+       assert(i==10);
+
+       assert(bdecode_integer(str2,sizeof(str2)-1,&i)==3);
+       assert(i==0);
+
+       assert(bdecode_integer(str3,sizeof(str3)-1,&i)==-1);
+
+       assert(bdecode_integer(str4,sizeof(str4)-1,&i)==16);
+       assert(i==10928390128301);
+}
+
+static void bdecode_string_basic_test() {
+       uint8_t buf[1024];
+       uint8_t str1[] = "4:spam";
+
+       assert(bdecode_string(NULL,sizeof(str1)-1,buf,1024)==-1);
+       assert(bdecode_string(str1,0,buf,1024)==-1);
+       assert(bdecode_string(str1,sizeof(str1)-1,NULL,1024)==-1);
+       assert(bdecode_string(str1,sizeof(str1)-1,buf,0)==-1);
+       assert(bdecode_string(str1,sizeof(str1)-1,buf,3)==-1);
+       assert(bdecode_string(str1,sizeof(str1)-1,buf,4)==4);
+       assert(bdecode_string(str1,sizeof(str1)-1,buf,1024)==4);
+}
+
+static void bdecode_type_basic_test() {
+       uint8_t str1[] = "4:spam";
+       uint8_t str2[] = "i12093e";
+       uint8_t str3[] = "l4:spam4:eggse";
+       uint8_t str4[] = "d3:cow3:moo4:spam4:eggse";
+
+       assert(BENCODE_STRING==bdecode_type(str1,sizeof(str1)-1));
+       assert(BENCODE_INTEGER==bdecode_type(str2,sizeof(str2)-1));
+       assert(BENCODE_LIST==bdecode_type(str3,sizeof(str3)-1));
+       assert(BENCODE_DICTIONARY==bdecode_type(str4,sizeof(str4)-1));
+}
+
+static void bencode_dict_basic_test() {
+       uint8_t buf[1024];
+       uint8_t *p;
+
+       memset(buf,0,1024);
+
+       p = buf;
+       assert(bencode_dict_start(NULL,1024)==-1);
+       assert(bencode_dict_start(p,0)==-1);
+       assert(bencode_dict_start(p,1024)==1);
+       p++;
+
+       uint8_t str1[] = "cow";
+       assert(bencode_string(str1,3,p,1023)==5);
+       p += 5;
+
+       uint8_t str2[] = "moo";
+       assert(bencode_string(str2,3,p,1018)==5);
+       p += 5;
+
+       uint8_t str3[] = "spam";
+       assert(bencode_string(str3,4,p,1013)==6);
+       p += 6;
+
+       uint8_t str4[] = "eggs";
+       assert(bencode_string(str4,4,p,1007)==6);
+       p += 6;
+       
+       assert(bencode_dict_end(NULL,1001)==-1);
+       assert(bencode_dict_end(p,0)==-1);
+       assert(bencode_dict_end(p,1001)==1);
+
+       assert(memcmp(buf,"d3:cow3:moo4:spam4:eggse",24)==0);
+}
+
+static void bencode_list_basic_test() {
+       uint8_t buf[1024];
+       uint8_t *p;
+
+       memset(buf,0,1024);
+
+       p = buf;
+       assert(bencode_list_start(NULL,1024)==-1);
+       assert(bencode_list_start(p,0)==-1);
+       assert(bencode_list_start(p,1024)==1);
+       p++;
+
+       uint8_t str1[] = "spam";
+       assert(bencode_string(str1,4,p,1023)==6);
+       p += 6;
+
+       uint8_t str2[] = "eggs";
+       assert(bencode_string(str2,4,p,1017)==6);
+       p += 6;
+
+       assert(bencode_list_end(NULL,1011)==-1);
+       assert(bencode_list_end(p,0)==-1);
+       assert(bencode_list_end(p,1011)==1);
+
+       assert(memcmp(buf,"l4:spam4:eggse",14)==0);
+}
+
+static void bencode_string_basic_test() {
+       uint8_t buf[1024];
+
+       memset(buf,0,1024);
+
+       uint8_t str1[] = "testlkajslfkdjasdfl test string";
+       assert(bencode_string(NULL,31,buf,1024)==-1);
+       assert(bencode_string(str1,0,buf,1024)==-1);
+       assert(bencode_string(str1,31,NULL,1024)==-1);
+       assert(bencode_string(str1,31,buf,0)==-1);
+       assert(bencode_string(str1,31,buf,1024)==34);
+
+       assert(memcmp("31:testlkajslfkdjasdfl test string",buf,34)==0);
+}
index da41854c789c845fdc1cd4d496e4ba98d1a00cf4..70140a429594b8a18cc07f20d35fdfc8a04a11ef 100644 (file)
@@ -33,11 +33,11 @@ static void torrent_add_basic_test() {
        assert(torrent_add(torrent,file3)==1);
        assert(torrent_add(torrent,file4)==1);
 
-       assert(strcmp(torrent->file_tree->directories->name,TEST_DIRECTORY)==0);
-       assert(torrent->file_tree->directories->files->file==file3);
-       assert(torrent->file_tree->directories->files->next->file==file4);
-       assert(torrent->file_tree->directories->files->next->next->file==file1);
-       assert(torrent->file_tree->directories->files->next->next->next->file==file2);
+       assert(strcmp(torrent->tree->directories->name,TEST_DIRECTORY)==0);
+       assert(torrent->tree->directories->files->file==file3);
+       assert(torrent->tree->directories->files->next->file==file4);
+       assert(torrent->tree->directories->files->next->next->file==file1);
+       assert(torrent->tree->directories->files->next->next->next->file==file2);
 
        torrent_free(torrent);