iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / protocol / bittorrent / bencoding.c
blob4765e9d5d7a8005349cf824df32bead71bfa9de9
1 /* BitTorrent bencoding scanner and parser */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <errno.h>
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
13 #include <sys/types.h>
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
16 #endif
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
22 #include "elinks.h"
24 #include "protocol/bittorrent/bencoding.h"
25 #include "protocol/bittorrent/common.h"
26 #include "util/error.h"
27 #include "util/sha1.h"
28 #include "util/scanner.h"
29 #include "util/string.h"
30 #include "util/time.h"
33 /* The various token types and what they contain. */
34 enum bencoding_token {
35 /* Char tokens: */
37 /* Char tokens range from 1 to 255 and have their char value as type */
38 /* meaning non char tokens have values from 256 and up. */
40 BENCODING_TOKEN_INTEGER = 'i', /* 'i' <integer> 'e' */
41 BENCODING_TOKEN_LIST = 'l', /* 'l' ( <any> ) * 'e' */
42 BENCODING_TOKEN_DICTIONARY = 'd', /* 'd' ( <string> <any> ) * 'e' */
43 BENCODING_TOKEN_END = 'e',
46 /* Low level tokens: */
48 BENCODING_TOKEN_STRING = 256, /* <integer> ':' <bytes> */
50 /* High level tokens: */
52 /* Common tokens. */
53 BENCODING_TOKEN_FILES, /* dictionary */
54 BENCODING_TOKEN_NAME, /* string */
56 /* Tokens related to the metainfo file. */
57 BENCODING_TOKEN_ANNOUNCE, /* string */
58 BENCODING_TOKEN_ANNOUNCE_LIST, /* list */
59 BENCODING_TOKEN_COMMENT, /* string */
60 BENCODING_TOKEN_CREATED_BY, /* string */
61 BENCODING_TOKEN_CREATION_DATE, /* integer */
62 BENCODING_TOKEN_INFO, /* dictionary */
63 BENCODING_TOKEN_LENGTH, /* integer */
64 BENCODING_TOKEN_MD5SUM, /* string */
65 BENCODING_TOKEN_PATH, /* string */
66 BENCODING_TOKEN_PIECES, /* string */
67 BENCODING_TOKEN_PIECE_LENGTH, /* integer */
69 /* Tokens related to the tracker protocol response. */
70 BENCODING_TOKEN_FAILURE_REASON, /* string */
71 BENCODING_TOKEN_INTERVAL, /* integer */
72 BENCODING_TOKEN_IP, /* string */
73 BENCODING_TOKEN_PEERS, /* dictionary */
74 BENCODING_TOKEN_PEER_ID, /* string */
75 BENCODING_TOKEN_PORT, /* integer */
77 /* Tokens related to the tracker `scrape' response. */
78 BENCODING_TOKEN_COMPLETE, /* integer */
79 BENCODING_TOKEN_DOWNLOADED, /* integer */
80 BENCODING_TOKEN_INCOMPLETE, /* integer */
82 /* Another internal token type used both to mark unused tokens in the
83 * scanner table as invalid or when scanning to signal that the
84 * scanning should end. */
85 BENCODING_TOKEN_NONE = 0,
87 /* Special token to report syntax errors. */
88 BENCODING_TOKEN_ERROR = 1,
92 /* ************************************************************************** */
93 /* The scanner: */
94 /* ************************************************************************** */
96 #define is_bencoding_integer(c) ((c) == BENCODING_TOKEN_INTEGER)
97 #define is_bencoding_list(c) ((c) == BENCODING_TOKEN_LIST)
98 #define is_bencoding_dictionary(c) ((c) == BENCODING_TOKEN_DICTIONARY)
99 #define is_bencoding_end(c) ((c) == BENCODING_TOKEN_END)
100 #define is_bencoding_string(c) (isdigit(c))
102 #define scan_bencoding_integer(scanner, s) \
103 while ((s) < (scanner)->end && isdigit(*(s))) (s)++;
105 static inline void
106 scan_bencoding_token(struct scanner *scanner, struct scanner_token *token)
108 const unsigned char *string = scanner->position;
109 unsigned char first_char = *string;
110 enum bencoding_token type = BENCODING_TOKEN_NONE;
111 int real_length = -1;
113 token->string = string++;
115 if (is_bencoding_string(first_char)) {
116 unsigned long string_length;
118 scan_bencoding_integer(scanner, string);
120 /* Check the length delimiter. */
121 if (*string == ':') {
122 errno = 0;
123 string_length = strtoul(token->string, NULL, 10);
124 if (!errno
125 && string_length < INT_MAX
126 && string + string_length < scanner->end) {
127 /* Claim the string data. */
128 token->string = string + 1;
129 real_length = string_length;
130 string = token->string + string_length;
131 type = BENCODING_TOKEN_STRING;
135 } else if (is_bencoding_end(first_char)) {
136 type = BENCODING_TOKEN_END;
138 } else if (is_bencoding_integer(first_char)) {
139 const unsigned char *integer_start = string;
141 /* Signedness. */
142 if (*string == '-') string++;
144 /* Scan to the end marker */
145 scan_bencoding_integer(scanner, string);
147 if (*string == BENCODING_TOKEN_END) {
148 token->string = integer_start;
149 real_length = string - integer_start;
150 type = BENCODING_TOKEN_INTEGER;
151 string++;
154 } else if (is_bencoding_dictionary(first_char)) {
155 type = BENCODING_TOKEN_DICTIONARY;
157 } else if (is_bencoding_list(first_char)) {
158 type = BENCODING_TOKEN_LIST;
161 token->type = type;
162 token->length = real_length > 0 ? real_length : string - token->string;
163 scanner->position = string;
166 static void
167 skip_bencoding_tokens(struct scanner *scanner)
169 int nesting_level = 0;
171 assert(scanner_has_tokens(scanner));
173 /* Skip while nesting_level is > 0 since the first token can be the end
174 * token. */
175 do {
176 struct scanner_token *token = get_scanner_token(scanner);
178 if (!token) return;
180 switch (token->type) {
181 case BENCODING_TOKEN_INTEGER:
182 case BENCODING_TOKEN_STRING:
183 break;
185 case BENCODING_TOKEN_DICTIONARY:
186 case BENCODING_TOKEN_LIST:
187 nesting_level++;
188 break;
190 case BENCODING_TOKEN_END:
191 nesting_level--;
192 break;
194 default:
195 INTERNAL("Scanner error detected");
198 skip_scanner_token(scanner);
200 } while (nesting_level > 0 && scanner_has_tokens(scanner));
203 static struct scanner_token *
204 scan_bencoding_tokens(struct scanner *scanner)
206 struct scanner_token *table_end = scanner->table + SCANNER_TOKENS;
207 struct scanner_token *current;
209 if (!begin_token_scanning(scanner))
210 return get_scanner_token(scanner);
212 /* Scan tokens until we fill the table */
213 for (current = scanner->table + scanner->tokens;
214 current < table_end && scanner->position < scanner->end;
215 current++) {
216 if (scanner->position >= scanner->end) break;
218 scan_bencoding_token(scanner, current);
220 /* Did someone scream for us to end the madness? */
221 if (current->type == BENCODING_TOKEN_NONE) {
222 scanner->position = NULL;
223 current--;
224 break;
228 return end_token_scanning(scanner, current);
232 struct scanner_info bencoding_scanner_info = {
233 NULL,
234 NULL,
235 scan_bencoding_tokens,
239 /* ************************************************************************** */
240 /* BitTorrent specific dictionary value type checking: */
241 /* ************************************************************************** */
243 struct bencoding_dictionary_info {
244 unsigned char *key;
245 enum bencoding_token key_type;
246 enum bencoding_token value_type;
249 #define DICT(key, keytype, valuetype) \
250 { key, BENCODING_TOKEN_##keytype, BENCODING_TOKEN_##valuetype }
252 static const struct bencoding_dictionary_info bencoding_dictionary_entries[] = {
253 /* <key> <key-type> <value-type> */
254 DICT("announce list", ANNOUNCE_LIST, LIST),
255 DICT("announce", ANNOUNCE, STRING),
256 DICT("comment", COMMENT, STRING),
257 DICT("complete", COMPLETE, INTEGER),
258 DICT("created by", CREATED_BY, STRING),
259 DICT("creation date", CREATION_DATE, INTEGER),
260 DICT("downloaded", DOWNLOADED, INTEGER),
261 DICT("failure reason", FAILURE_REASON, STRING),
262 DICT("files", FILES, LIST),
263 DICT("incomplete", INCOMPLETE, INTEGER),
264 DICT("info", INFO, DICTIONARY),
265 DICT("interval", INTERVAL, INTEGER),
266 DICT("ip", IP, STRING),
267 DICT("length", LENGTH, INTEGER),
268 DICT("md5sum", MD5SUM, STRING),
269 DICT("name", NAME, STRING),
270 DICT("path", PATH, LIST),
271 DICT("peer id", PEER_ID, STRING),
272 DICT("peers", PEERS, LIST),
273 DICT("peers", PEERS, STRING),
274 DICT("piece length", PIECE_LENGTH, INTEGER),
275 DICT("pieces", PIECES, STRING),
276 DICT("port", PORT, INTEGER),
278 DICT(NULL, NONE, NONE),
281 #undef DICT
283 /* Looks up the key type and validates that the value token is valid. */
284 enum bencoding_token
285 check_bencoding_dictionary_entry(struct scanner *scanner,
286 struct scanner_token **value_ptr)
288 const struct bencoding_dictionary_info *entry;
289 struct scanner_token *key, *value, key_backup;
291 key = get_scanner_token(scanner);
292 if (!key) return BENCODING_TOKEN_ERROR;
294 if (key->type == BENCODING_TOKEN_END)
295 return BENCODING_TOKEN_END;
297 if (key->type != BENCODING_TOKEN_STRING)
298 return BENCODING_TOKEN_NONE;
300 /* Backup the token since the it might disappear when requesting the
301 * following value token. */
302 copy_struct(&key_backup, key);
303 key = &key_backup;
305 *value_ptr = value = get_next_scanner_token(scanner);
306 if (!value) return BENCODING_TOKEN_ERROR;
308 for (entry = bencoding_dictionary_entries; entry->key; entry++) {
309 if (!scanner_token_strlcasecmp(key, entry->key, -1))
310 continue;
312 /* Type-check the value. Some keys have multiple types. */
313 if (value->type != entry->value_type)
314 continue;
316 return entry->key_type;
319 return BENCODING_TOKEN_NONE;
323 /* ************************************************************************** */
324 /* The .torrent metafile parsing: */
325 /* ************************************************************************** */
327 static off_t
328 parse_bencoding_integer(struct scanner_token *token)
330 const unsigned char *string = token->string;
331 int pos = 0, length = token->length;
332 off_t integer = 0;
333 int sign = 1;
335 assert(length);
337 if (string[pos] == '-') {
338 pos++;
339 sign = -1;
342 for (; pos < length && isdigit(string[pos]); pos++) {
343 off_t newint = integer * 10 + string[pos] - '0';
345 /* Check for overflow. This assumes wraparound,
346 * even though C does not guarantee that. */
347 if (newint / 10 != integer)
348 return 0;
349 integer = newint;
352 if (sign == -1)
353 integer *= sign;
355 return integer;
358 static unsigned char *
359 normalize_bencoding_path(const unsigned char *path, int pathlen,
360 int *malicious)
362 struct string string;
364 /* Normalize and check for malicious paths in the the file list. */
366 if (!init_string(&string)
367 || !add_to_string(&string, "file://./")
368 || !add_bytes_to_string(&string, path, pathlen)) {
369 done_string(&string);
370 return NULL;
373 path = normalize_uri(NULL, string.source);
375 /* This shouldn't happened but it makes sense to be a little paranoid
376 * here. ;-) */
377 if (memcmp(path, "file://", 7)) {
378 done_string(&string);
379 return NULL;
382 /* The normalization will make the path start with './' if the path is
383 * OK and '/' if the path contained directory elevators which moved
384 * outside the current working directory (CWD). These potentially
385 * malicous paths will be translated to just be nested in the CWD. */
386 *malicious = !!dir_sep(path[7]);
388 path += 8 + !*malicious;
389 memmove(string.source, path, strlen(path) + 1);
391 return string.source;
394 /* Add file to the file list. The new file is based on info from the passed
395 * template and will have the given path after it has been normalized and
396 * checked for sanity. */
397 static enum bittorrent_state
398 add_bittorrent_file(struct bittorrent_meta *meta, unsigned char *path,
399 struct bittorrent_file *template)
401 struct bittorrent_file *file;
402 int malicious;
403 int pathlen;
405 /* Normalize and check for malicious paths in the the file list. */
406 path = normalize_bencoding_path(path, strlen(path), &malicious);
407 if (!path) return BITTORRENT_STATE_OUT_OF_MEM;
409 if (malicious)
410 meta->malicious_paths = malicious;
412 pathlen = strlen(path);
414 file = mem_calloc(1, sizeof(*file) + pathlen);
415 if (!file) {
416 mem_free(path);
417 return BITTORRENT_STATE_OUT_OF_MEM;
420 copy_struct(file, template);
421 memcpy(file->name, path, pathlen);
422 mem_free(path);
424 file->selected = 1;
426 add_to_list_end(meta->files, file);
428 return BITTORRENT_STATE_OK;
431 /* Parses a list of path elements and adds them each to the path string
432 * separated by the platform specific directory separater. */
433 static enum bittorrent_state
434 parse_bencoding_file_path(struct scanner *scanner, struct string *path)
436 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_LIST);
438 skip_scanner_token(scanner);
440 while (scanner_has_tokens(scanner)) {
441 struct scanner_token *token = get_scanner_token(scanner);
443 if (!token) break;
445 if (token->type == BENCODING_TOKEN_END) {
446 return BITTORRENT_STATE_OK;
449 if (token->type != BENCODING_TOKEN_STRING)
450 break;
452 if (path->length > 0) {
453 /* Somewhat platform independant. dir_sep() is either a
454 * macro or an inline function so the compiler should
455 * optimize away the unneded branch. */
456 unsigned char separator = dir_sep('\\') ? '\\' : '/';
458 add_char_to_string(path, separator);
461 add_bytes_to_string(path, token->string, token->length);
462 skip_scanner_token(scanner);
465 return BITTORRENT_STATE_ERROR;
468 /* Parse a dictionary of file information used for multi-file torrents. */
469 static enum bittorrent_state
470 parse_bencoding_file_dictionary(struct bittorrent_meta *meta,
471 struct scanner *scanner, struct string *path)
473 struct bittorrent_file file;
475 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_DICTIONARY);
477 skip_scanner_token(scanner);
479 memset(&file, 0, sizeof(file));
481 while (scanner_has_tokens(scanner)) {
482 struct scanner_token *value;
483 enum bittorrent_state state;
485 switch (check_bencoding_dictionary_entry(scanner, &value)) {
486 case BENCODING_TOKEN_PATH:
487 state = parse_bencoding_file_path(scanner, path);
488 if (state != BITTORRENT_STATE_OK)
489 return state;
490 skip_scanner_token(scanner);
491 break;
493 case BENCODING_TOKEN_LENGTH:
494 file.length = parse_bencoding_integer(value);
495 skip_scanner_token(scanner);
496 break;
498 case BENCODING_TOKEN_MD5SUM:
499 if (value->length != sizeof(md5_digest_hex_T))
500 return BITTORRENT_STATE_ERROR;
502 memcpy(file.md5sum, value->string, value->length);
503 skip_scanner_token(scanner);
504 break;
506 case BENCODING_TOKEN_END:
507 skip_scanner_token(scanner);
508 return add_bittorrent_file(meta, path->source, &file);
510 case BENCODING_TOKEN_ERROR:
511 return BITTORRENT_STATE_ERROR;
513 case BENCODING_TOKEN_NONE:
514 default:
515 skip_bencoding_tokens(scanner);
519 return BITTORRENT_STATE_ERROR;
522 /* Parse a list of file dictionaries. */
523 static enum bittorrent_state
524 parse_bencoding_files_list(struct bittorrent_meta *meta, struct scanner *scanner)
526 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_LIST);
528 skip_scanner_token(scanner);
530 while (scanner_has_tokens(scanner)) {
531 struct scanner_token *token = get_scanner_token(scanner);
532 struct string path;
533 enum bittorrent_state state;
535 if (!token) break;
537 if (token->type == BENCODING_TOKEN_END) {
538 skip_scanner_token(scanner);
539 return BITTORRENT_STATE_OK;
542 if (token->type != BENCODING_TOKEN_DICTIONARY)
543 return BITTORRENT_STATE_ERROR;
545 /* Allocating and freeing the path string here makes error
546 * handling so much easier in parse_bencoding_file_dictionary()
547 * because it can return right away. */
548 if (!init_string(&path))
549 return BITTORRENT_STATE_OUT_OF_MEM;
551 state = parse_bencoding_file_dictionary(meta, scanner, &path);
552 done_string(&path);
553 if (state != BITTORRENT_STATE_OK)
554 return state;
557 return BITTORRENT_STATE_ERROR;
560 /* Parse the info dictionary which contains file and piece infomation. */
561 static enum bittorrent_state
562 parse_bencoding_info_dictionary(struct bittorrent_meta *meta,
563 struct scanner *scanner)
565 struct bittorrent_file file;
567 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_DICTIONARY);
569 skip_scanner_token(scanner);
571 memset(&file, 0, sizeof(file));
573 while (scanner_has_tokens(scanner)) {
574 struct scanner_token *value;
575 enum bittorrent_state state;
576 int malicious;
577 off_t length;
579 switch (check_bencoding_dictionary_entry(scanner, &value)) {
580 case BENCODING_TOKEN_NAME:
581 meta->name = normalize_bencoding_path(value->string,
582 value->length,
583 &malicious);
584 if (!meta->name) return BITTORRENT_STATE_OUT_OF_MEM;
585 if (malicious)
586 meta->malicious_paths = malicious;
587 skip_scanner_token(scanner);
588 break;
590 case BENCODING_TOKEN_PIECES:
591 /* The piece hash must be a multiple of the SHA digest
592 * length. */
593 if ((value->length % SHA_DIGEST_LENGTH) != 0)
594 return BITTORRENT_STATE_ERROR;
596 meta->pieces = value->length / SHA_DIGEST_LENGTH;
597 meta->piece_hash = memacpy(value->string, value->length);
598 skip_scanner_token(scanner);
599 break;
601 case BENCODING_TOKEN_PIECE_LENGTH:
602 length = parse_bencoding_integer(value);
603 if (length < 0 || length >= INT_MAX)
604 return BITTORRENT_STATE_ERROR;
606 meta->piece_length = (uint32_t) length;
607 skip_scanner_token(scanner);
608 break;
610 case BENCODING_TOKEN_FILES:
611 meta->type = BITTORRENT_MULTI_FILE;
612 state = parse_bencoding_files_list(meta, scanner);
613 if (state != BITTORRENT_STATE_OK)
614 return state;
615 break;
617 case BENCODING_TOKEN_LENGTH:
618 file.length = parse_bencoding_integer(value);
619 skip_scanner_token(scanner);
620 break;
622 case BENCODING_TOKEN_MD5SUM:
623 if (value->length != 32)
624 return BITTORRENT_STATE_ERROR;
626 memcpy(file.md5sum, value->string, value->length);
627 skip_scanner_token(scanner);
628 break;
630 case BENCODING_TOKEN_END:
631 /* All file info was saved from the 'files' list. */
632 if (meta->type == BITTORRENT_MULTI_FILE)
633 return BITTORRENT_STATE_OK;
635 if (!meta->name)
636 return BITTORRENT_STATE_ERROR;
638 return add_bittorrent_file(meta, meta->name, &file);
640 case BENCODING_TOKEN_ERROR:
641 return BITTORRENT_STATE_ERROR;
643 case BENCODING_TOKEN_NONE:
644 default:
645 skip_bencoding_tokens(scanner);
649 /* Check if all requirements were met. */
650 return BITTORRENT_STATE_ERROR;
653 /* Validate that the bencoded metainfo file contained all the required fields
654 * and that their values are sane. */
655 static enum bittorrent_state
656 check_bittorrent_metafile(struct bittorrent_meta *meta)
658 struct bittorrent_file *file;
659 off_t last_piece_length = 0;
660 off_t total_length = 0;
662 if (bittorrent_id_is_empty(meta->info_hash)
663 || !meta->pieces
664 || !meta->name
665 || !meta->name[0]
666 || !meta->piece_hash
667 || !meta->piece_length
668 || !meta->tracker_uris.size
669 || list_empty(meta->files))
670 return BITTORRENT_STATE_ERROR;
672 /* FIXME: Should we also check if any two files have the same name? */
673 foreach (file, meta->files) {
674 if (file->length < 0 || !file->name)
675 return BITTORRENT_STATE_ERROR;
677 total_length += file->length;
680 last_piece_length = (off_t) total_length % meta->piece_length;
681 if (!last_piece_length)
682 last_piece_length = meta->piece_length;
684 meta->last_piece_length = (uint32_t) last_piece_length;
686 /* Check that the non-zero last_piece_length can be stored. */
687 if (meta->last_piece_length != last_piece_length)
688 return BITTORRENT_STATE_ERROR;
690 return BITTORRENT_STATE_OK;
693 enum bittorrent_state
694 parse_bittorrent_metafile(struct bittorrent_meta *meta,
695 struct bittorrent_const_string *metafile)
697 struct scanner scanner;
699 memset(meta, 0, sizeof(*meta));
700 init_list(meta->files);
702 init_scanner(&scanner, &bencoding_scanner_info,
703 metafile->source, metafile->source + metafile->length);
706 struct scanner_token *token = get_scanner_token(&scanner);
708 if (!token || token->type != BENCODING_TOKEN_DICTIONARY)
709 return BITTORRENT_STATE_ERROR;
711 skip_scanner_token(&scanner);
714 while (scanner_has_tokens(&scanner)) {
715 struct scanner_token *value;
717 switch (check_bencoding_dictionary_entry(&scanner, &value)) {
718 case BENCODING_TOKEN_ANNOUNCE:
720 unsigned char *value_string;
721 struct uri *uri;
723 value_string = memacpy(value->string, value->length);
724 skip_scanner_token(&scanner);
726 if (!value_string) break;
728 uri = get_uri(value_string, 0);
729 mem_free(value_string);
730 if (uri) {
731 add_to_uri_list(&meta->tracker_uris, uri);
732 done_uri(uri);
734 break;
736 case BENCODING_TOKEN_ANNOUNCE_LIST:
737 /* FIXME: Add to the tracker URI list, when/if multiple
738 * trackers are/will be supported. */
739 skip_bencoding_tokens(&scanner);
740 break;
742 case BENCODING_TOKEN_INFO:
744 const unsigned char *start = value->string;
745 struct scanner_token *token;
746 enum bittorrent_state state;
748 state = parse_bencoding_info_dictionary(meta, &scanner);
749 if (state != BITTORRENT_STATE_OK)
750 return BITTORRENT_STATE_ERROR;
752 token = get_scanner_token(&scanner);
753 assert(token && token->type == BENCODING_TOKEN_END);
755 /* Digest the dictionary to create the info hash. */
756 SHA1(start, token->string + token->length - start,
757 meta->info_hash);
759 skip_scanner_token(&scanner);
760 break;
762 case BENCODING_TOKEN_COMMENT:
763 meta->comment = memacpy(value->string,
764 int_min(value->length, MAX_STR_LEN));
765 skip_scanner_token(&scanner);
766 break;
768 case BENCODING_TOKEN_CREATION_DATE:
769 /* Bug 923: Assumes time_t values fit in off_t. */
770 meta->creation_date = (time_t) parse_bencoding_integer(value);
771 skip_scanner_token(&scanner);
772 break;
774 case BENCODING_TOKEN_CREATED_BY:
775 skip_scanner_token(&scanner);
776 break;
778 case BENCODING_TOKEN_END:
779 /* Check if all requirements were met. */
780 return check_bittorrent_metafile(meta);
782 case BENCODING_TOKEN_ERROR:
783 return BITTORRENT_STATE_ERROR;
785 case BENCODING_TOKEN_NONE:
786 default:
787 skip_bencoding_tokens(&scanner);
791 return BITTORRENT_STATE_ERROR;
795 /* ************************************************************************** */
796 /* Tracker response parsing: */
797 /* ************************************************************************** */
799 static enum bittorrent_state
800 parse_bencoding_peer_dictionary(struct bittorrent_connection *bittorrent,
801 struct scanner *scanner)
803 struct scanner_token ip;
804 bittorrent_id_T id;
805 /* Set to invalid value. */
806 int port = -1;
808 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_DICTIONARY);
810 skip_scanner_token(scanner);
812 memset(id, 0, sizeof(bittorrent_id_T));
813 memset(&ip, 0, sizeof(ip));
815 while (scanner_has_tokens(scanner)) {
816 struct scanner_token *value;
818 switch (check_bencoding_dictionary_entry(scanner, &value)) {
819 case BENCODING_TOKEN_IP:
820 copy_struct(&ip, value);
821 skip_scanner_token(scanner);
822 break;
824 case BENCODING_TOKEN_PORT:
825 port = (int) parse_bencoding_integer(value);
826 skip_scanner_token(scanner);
827 break;
829 case BENCODING_TOKEN_PEER_ID:
830 if (value->length != sizeof(bittorrent_id_T))
831 return BITTORRENT_STATE_ERROR;
833 memcpy(id, value->string, value->length);
834 skip_scanner_token(scanner);
835 break;
837 case BENCODING_TOKEN_END:
838 skip_scanner_token(scanner);
839 return add_peer_to_bittorrent_pool(bittorrent, id, port,
840 ip.string, ip.length);
842 case BENCODING_TOKEN_ERROR:
843 return BITTORRENT_STATE_ERROR;
845 case BENCODING_TOKEN_NONE:
846 default:
847 skip_bencoding_tokens(scanner);
851 return BITTORRENT_STATE_ERROR;
854 static enum bittorrent_state
855 parse_bencoding_peers_list(struct bittorrent_connection *bittorrent,
856 struct scanner *scanner)
858 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_LIST);
860 skip_scanner_token(scanner);
862 while (scanner_has_tokens(scanner)) {
863 struct scanner_token *token = get_scanner_token(scanner);
864 enum bittorrent_state state;
866 if (!token) break;
868 if (token->type == BENCODING_TOKEN_END)
869 return BITTORRENT_STATE_OK;
871 if (token->type != BENCODING_TOKEN_DICTIONARY)
872 return BITTORRENT_STATE_ERROR;
874 state = parse_bencoding_peer_dictionary(bittorrent, scanner);
875 if (state != BITTORRENT_STATE_OK)
876 return state;
879 return BITTORRENT_STATE_ERROR;
882 /* Parses the compact peer list format. It is a string made up of substrings of
883 * length 6, where the first 4 bytes hold the IP address and the 2 last bytes
884 * hold the port number. */
885 static enum bittorrent_state
886 parse_bencoding_peers_string(struct bittorrent_connection *bittorrent,
887 struct scanner *scanner)
889 struct scanner_token *token = get_scanner_token(scanner);
890 const unsigned char *pos;
891 const unsigned char *last_peer_info_start
892 = token->string + token->length - 6;
893 enum bittorrent_state state = BITTORRENT_STATE_OK;
895 assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_STRING);
897 for (pos = token->string; pos <= last_peer_info_start; pos += 6) {
898 /* Only IPv4 strings can occur in this format. */
899 unsigned char ip[INET_ADDRSTRLEN];
900 int iplen;
901 uint16_t port;
903 iplen = snprintf(ip, sizeof(ip), "%d.%d.%d.%d",
904 (int) pos[0], (int) pos[1],
905 (int) pos[2], (int) pos[3]);
907 memcpy(&port, pos + 4, sizeof(port));
908 port = ntohs(port);
910 state = add_peer_to_bittorrent_pool(bittorrent, NULL, port,
911 ip, iplen);
912 if (state != BITTORRENT_STATE_OK)
913 break;
916 return state;
919 enum bittorrent_state
920 parse_bittorrent_tracker_response(struct bittorrent_connection *bittorrent,
921 struct bittorrent_const_string *response)
923 struct scanner scanner;
925 init_scanner(&scanner, &bencoding_scanner_info,
926 response->source, response->source + response->length);
929 struct scanner_token *token = get_scanner_token(&scanner);
931 if (!token || token->type != BENCODING_TOKEN_DICTIONARY)
932 return BITTORRENT_STATE_ERROR;
934 skip_scanner_token(&scanner);
937 while (scanner_has_tokens(&scanner)) {
938 struct scanner_token *value;
939 enum bittorrent_state state;
940 off_t integer;
942 switch (check_bencoding_dictionary_entry(&scanner, &value)) {
943 case BENCODING_TOKEN_FAILURE_REASON:
944 response->source = value->string;
945 response->length = value->length;
947 return BITTORRENT_STATE_REQUEST_FAILURE;
949 case BENCODING_TOKEN_INTERVAL:
950 bittorrent->tracker.interval = (int) parse_bencoding_integer(value);
951 skip_scanner_token(&scanner);
952 break;
954 case BENCODING_TOKEN_COMPLETE:
955 integer = parse_bencoding_integer(value);
956 if (0 < integer && integer < INT_MAX)
957 bittorrent->complete = (uint32_t) integer;
958 skip_scanner_token(&scanner);
959 break;
961 case BENCODING_TOKEN_INCOMPLETE:
962 integer = parse_bencoding_integer(value);
963 if (0 < integer && integer < INT_MAX)
964 bittorrent->incomplete = (uint32_t) integer;
965 skip_scanner_token(&scanner);
966 break;
968 case BENCODING_TOKEN_PEERS:
969 /* There are two formats: the normal list and the more
970 * compact string variant. */
971 switch (value->type) {
972 case BENCODING_TOKEN_LIST:
973 state = parse_bencoding_peers_list(bittorrent, &scanner);
974 if (state != BITTORRENT_STATE_OK)
975 return state;
977 assert(get_scanner_token(&scanner)
978 && get_scanner_token(&scanner)->type
979 == BENCODING_TOKEN_END);
980 break;
982 case BENCODING_TOKEN_STRING:
983 /* Parse peer list when using compact format. */
984 state = parse_bencoding_peers_string(bittorrent, &scanner);
985 if (state != BITTORRENT_STATE_OK)
986 return state;
987 assert(get_scanner_token(&scanner) == value);
988 break;
990 default:
991 return BITTORRENT_STATE_ERROR;
994 skip_scanner_token(&scanner);
995 break;
997 case BENCODING_TOKEN_END:
998 /* TODO: Check if all requirements were met. */
999 return BITTORRENT_STATE_OK;
1001 case BENCODING_TOKEN_ERROR:
1002 return BITTORRENT_STATE_ERROR;
1004 case BENCODING_TOKEN_NONE:
1005 default:
1006 skip_bencoding_tokens(&scanner);
1010 return BITTORRENT_STATE_ERROR;