1 /* BitTorrent bencoding scanner and parser */
13 #include <sys/types.h>
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.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
{
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: */
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 /* ************************************************************************** */
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)++;
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
== ':') {
123 string_length
= strtoul(token
->string
, NULL
, 10);
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
;
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
;
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
;
162 token
->length
= real_length
> 0 ? real_length
: string
- token
->string
;
163 scanner
->position
= string
;
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
176 struct scanner_token
*token
= get_scanner_token(scanner
);
180 switch (token
->type
) {
181 case BENCODING_TOKEN_INTEGER
:
182 case BENCODING_TOKEN_STRING
:
185 case BENCODING_TOKEN_DICTIONARY
:
186 case BENCODING_TOKEN_LIST
:
190 case BENCODING_TOKEN_END
:
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
;
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
;
228 return end_token_scanning(scanner
, current
);
232 struct scanner_info bencoding_scanner_info
= {
235 scan_bencoding_tokens
,
239 /* ************************************************************************** */
240 /* BitTorrent specific dictionary value type checking: */
241 /* ************************************************************************** */
243 struct bencoding_dictionary_info
{
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
),
283 /* Looks up the key type and validates that the value token is valid. */
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
);
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))
312 /* Type-check the value. Some keys have multiple types. */
313 if (value
->type
!= entry
->value_type
)
316 return entry
->key_type
;
319 return BENCODING_TOKEN_NONE
;
323 /* ************************************************************************** */
324 /* The .torrent metafile parsing: */
325 /* ************************************************************************** */
328 parse_bencoding_integer(struct scanner_token
*token
)
330 const unsigned char *string
= token
->string
;
331 int pos
= 0, length
= token
->length
;
337 if (string
[pos
] == '-') {
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
)
358 static unsigned char *
359 normalize_bencoding_path(const unsigned char *path
, int pathlen
,
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
);
373 path
= normalize_uri(NULL
, string
.source
);
375 /* This shouldn't happened but it makes sense to be a little paranoid
377 if (memcmp(path
, "file://", 7)) {
378 done_string(&string
);
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
;
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
;
410 meta
->malicious_paths
= malicious
;
412 pathlen
= strlen(path
);
414 file
= mem_calloc(1, sizeof(*file
) + pathlen
);
417 return BITTORRENT_STATE_OUT_OF_MEM
;
420 copy_struct(file
, template);
421 memcpy(file
->name
, path
, pathlen
);
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
);
445 if (token
->type
== BENCODING_TOKEN_END
) {
446 return BITTORRENT_STATE_OK
;
449 if (token
->type
!= BENCODING_TOKEN_STRING
)
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
)
490 skip_scanner_token(scanner
);
493 case BENCODING_TOKEN_LENGTH
:
494 file
.length
= parse_bencoding_integer(value
);
495 skip_scanner_token(scanner
);
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
);
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
:
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
);
533 enum bittorrent_state state
;
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
);
553 if (state
!= BITTORRENT_STATE_OK
)
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
;
579 switch (check_bencoding_dictionary_entry(scanner
, &value
)) {
580 case BENCODING_TOKEN_NAME
:
581 meta
->name
= normalize_bencoding_path(value
->string
,
584 if (!meta
->name
) return BITTORRENT_STATE_OUT_OF_MEM
;
586 meta
->malicious_paths
= malicious
;
587 skip_scanner_token(scanner
);
590 case BENCODING_TOKEN_PIECES
:
591 /* The piece hash must be a multiple of the SHA digest
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
);
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
);
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
)
617 case BENCODING_TOKEN_LENGTH
:
618 file
.length
= parse_bencoding_integer(value
);
619 skip_scanner_token(scanner
);
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
);
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
;
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
:
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
)
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
;
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
);
731 add_to_uri_list(&meta
->tracker_uris
, uri
);
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
);
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
,
759 skip_scanner_token(&scanner
);
762 case BENCODING_TOKEN_COMMENT
:
763 meta
->comment
= memacpy(value
->string
,
764 int_min(value
->length
, MAX_STR_LEN
));
765 skip_scanner_token(&scanner
);
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
);
774 case BENCODING_TOKEN_CREATED_BY
:
775 skip_scanner_token(&scanner
);
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
:
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
;
805 /* Set to invalid value. */
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
);
824 case BENCODING_TOKEN_PORT
:
825 port
= (int) parse_bencoding_integer(value
);
826 skip_scanner_token(scanner
);
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
);
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
:
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
;
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
)
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
];
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
));
910 state
= add_peer_to_bittorrent_pool(bittorrent
, NULL
, port
,
912 if (state
!= BITTORRENT_STATE_OK
)
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
;
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
);
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
);
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
);
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
)
977 assert(get_scanner_token(&scanner
)
978 && get_scanner_token(&scanner
)->type
979 == BENCODING_TOKEN_END
);
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
)
987 assert(get_scanner_token(&scanner
) == value
);
991 return BITTORRENT_STATE_ERROR
;
994 skip_scanner_token(&scanner
);
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
:
1006 skip_bencoding_tokens(&scanner
);
1010 return BITTORRENT_STATE_ERROR
;