diff options
| author | Jesper Jensen <jesper@slashwin.dk> | 2021-08-29 00:47:32 +0200 |
|---|---|---|
| committer | Jesper Jensen <jesper@slashwin.dk> | 2021-08-29 00:47:32 +0200 |
| commit | 5471d80c5350f764ec53733bae9d32c0a1a339e0 (patch) | |
| tree | 1578cb3da331b1819a12eb3127ceb25baaa3cd36 /src | |
| parent | e00efb4381c5123699e4ef9807b67eba54ea06a0 (diff) | |
Add formal benc cursor
Diffstat (limited to 'src')
| -rw-r--r-- | src/benc.c | 98 | ||||
| -rw-r--r-- | src/benc.h | 18 | ||||
| -rw-r--r-- | src/log.h | 9 | ||||
| -rw-r--r-- | src/main.c | 30 |
4 files changed, 139 insertions, 16 deletions
@@ -175,6 +175,102 @@ int64_t benc_decode(const char** cursor, const char* end, int* depth, struct ben return cursor_out; } +int bcur_fill(struct bcursor* cursor) { + if(cursor->source == cursor->source_end) { + return EOF; + } + + int read = benc_decode(&cursor->source, cursor->source_end, &cursor->source_depth, cursor->base, cursor->base_len); + cursor->end = cursor->base + read; + + return 0; +} + +int bcur_open(struct bcursor* cursor, const char* source, const char* source_end, struct benc_node* buffer, size_t buffer_len) { + cursor->source = source; + (*((const char**)&cursor->source_end)) = source_end; + cursor->source_depth = 0; + + *((struct benc_node**)&cursor->base) = buffer; + *((size_t*)&cursor->base_len) = buffer_len; + cursor->readhead = buffer; + + return bcur_fill(cursor); +} + +int bcur_next(struct bcursor* cursor, uint32_t steps) { + cursor->readhead+=steps; + + // Check if we need to read more + if(cursor->readhead >= cursor->end) { + return bcur_fill(cursor); + } + return 0; +} + +int bcur_next_sibling(struct bcursor* cursor) { + assert(cursor->readhead->type == BNT_LIST || cursor->readhead->type == BNT_DICT); + + if(cursor->readhead->type == BNT_LIST || cursor->readhead->type == BNT_DICT) { + uint32_t tdepth = cursor->readhead->depth; + cursor->readhead++; + while(cursor->readhead->type != BNT_END || cursor->readhead->depth != tdepth) { + if(bcur_next(cursor, 1) != 0) { + fatal("Invalid dict/list"); + } + } + } + + return bcur_next(cursor, 1); +} + +// All the arrays should be equal length +ssize_t bcur_find_key(struct bcursor* cursor, const enum benc_nodetype* keyTypes, const char** keyValues, const size_t* keyLengths, const size_t keys) { + // @ROBUSTNESS: Check if keytypes are anything but strings and ints because that is not supported + int rc; + + while(true) { + // Skip lists + if(cursor->readhead->type == BNT_LIST || cursor->readhead->type == BNT_DICT) { + rc = bcur_next_sibling(cursor); + if(rc != 0) { + fatal("Invalid dict"); + } + } else { + // Check if the key one of the ones we are looking for + for(size_t i = 0; i < keys; i++) { + if(cursor->readhead->type == keyTypes[i] && memcmp(cursor->readhead->loc, keyValues[i], MIN(cursor->readhead->size, keyLengths[i])) == 0) { + return i; + } + } + } + + // Skip the key part + rc = bcur_next(cursor, 1); + if(rc != 0) { + fatal("Invalid dict"); + } + + if(cursor->readhead->type == BNT_LIST || cursor->readhead->type == BNT_DICT) { + // Skip a multitoken element + rc = bcur_next_sibling(cursor); + if(rc != 0) { + fatal("Invalid dict"); + } + } else { + // Skip a single token element + rc = bcur_next(cursor, 1); + if(rc != 0) { + fatal("Invalid dict"); + } + } + + if(cursor->readhead->type == BNT_END) { + return -1; + } + } +} + void skip_sibling(const struct benc_node** cursor, const struct benc_node* end) { assert((*cursor)->type == BNT_LIST || (*cursor)->type == BNT_DICT); @@ -204,7 +300,7 @@ ssize_t skip_to_key(const struct benc_node** cursor, const struct benc_node* end while(true) { if(*cursor > end-1) { - fatal("Invalid dict"); + return -1; } // Skip lists @@ -27,5 +27,23 @@ bool readint(const char** loc, int64_t* val); void benc_print(const struct benc_node* stream, size_t stream_len, int* depth); int64_t benc_decode(const char** cursor, const char* end, int* depth, struct benc_node* stream, size_t stream_len); +struct bcursor { + const char* source; + const char* const source_end; + int source_depth; + + struct benc_node* const base; + const size_t base_len; + + struct benc_node* readhead; + struct benc_node* end; +}; + +int bcur_open(struct bcursor* cursor, const char* source, const char* source_end, struct benc_node* buffer, size_t buffer_len); +int bcur_next(struct bcursor* cursor, uint32_t steps); +int bcur_next_sibling(struct bcursor* cursor); +ssize_t bcur_find_key(struct bcursor* cursor, const enum benc_nodetype* keyTypes, const char** keyValues, const size_t* keyLengths, const size_t keys); + void skip_sibling(const struct benc_node** cursor, const struct benc_node* end); ssize_t skip_to_key(const struct benc_node** cursor, const struct benc_node* end, const enum benc_nodetype* keyTypes, const char** keyValues, const size_t* keyLengths, const size_t keys); + @@ -13,8 +13,9 @@ printf(format "\n", ## __VA_ARGS__); \ fflush(stderr) -#define fatal(format, ...) \ - printf(format "\n", ## __VA_ARGS__); \ - fflush(stderr); \ - abort() +#define fatal(format, ...) do{\ + printf(format "\n", ## __VA_ARGS__); \ + fflush(stderr); \ + abort(); \ + } while(0) @@ -337,28 +337,36 @@ int main(int argc, char** argv) { struct benc_node* stream_cursor = stream; if(stream_cursor->type != BNT_DICT) { - err("Response is not a dict"); - exit(EXIT_FAILURE); + fatal("First value is not a dict"); } stream_cursor++; if(skip_to_key((const struct benc_node**)&stream_cursor, stream+len, (const enum benc_nodetype[]){BNT_STRING}, (const char*[]){"t"}, (const size_t[]){1}, 1) == -1) { - err("No t key in packet"); - exit(EXIT_FAILURE); + fatal("No t key in packet"); } stream_cursor++; - char char_buffer = stream_cursor->loc[stream_cursor->size]; - ((char*)stream_cursor->loc)[stream_cursor->size] = '\0'; - uint32_t transaction = strtol(stream_cursor->loc, NULL, 10); - ((char*)stream_cursor->loc)[stream_cursor->size] = char_buffer; + uint32_t transaction; + { + // Temporary null terminate the string to parse the number without a copy + char char_buffer = stream_cursor->loc[stream_cursor->size]; + ((char*)stream_cursor->loc)[stream_cursor->size] = '\0'; + char* end; + transaction = strtol(stream_cursor->loc, &end, 10); + ((char*)stream_cursor->loc)[stream_cursor->size] = char_buffer; + + if(end != stream_cursor->loc+stream_cursor->size) { + dbg("DISCARD: Transaction id is not a number %.*s", stream_cursor->size, stream->loc); + continue; + } + } uint16_t reqId; if(!find_req(transaction, &reqId)) { - err("No request with transaction ID %d", transaction); - exit(EXIT_FAILURE); + dbg("DISCARD: unknown transaction id %d", transaction); + continue; } - dbg("Transaction id matches requst %d", reqId); + dbg("Transaction id matches request %d", reqId); if(sockaddr_cmp(&requestdata[reqId].addr, (struct sockaddr*)&remote) != 0) { err("Unexpected IP for valid transaction"); |
