bencoding.c
来自「elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, el」· C语言 代码 · 共 1,000 行 · 第 1/2 页
C
1,000 行
case BENCODING_TOKEN_ERROR: return BITTORRENT_STATE_ERROR; case BENCODING_TOKEN_NONE: default: skip_bencoding_tokens(scanner); } } return BITTORRENT_STATE_ERROR;}/* Parse a list of file dictionaries. */static enum bittorrent_stateparse_bencoding_files_list(struct bittorrent_meta *meta, struct scanner *scanner){ assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_LIST); skip_scanner_token(scanner); while (scanner_has_tokens(scanner)) { struct scanner_token *token = get_scanner_token(scanner); struct string path; enum bittorrent_state state; if (!token) break; if (token->type == BENCODING_TOKEN_END) { skip_scanner_token(scanner); return BITTORRENT_STATE_OK; } if (token->type != BENCODING_TOKEN_DICTIONARY) return BITTORRENT_STATE_ERROR; /* Allocating and freeing the path string here makes error * handling so much easier in parse_bencoding_file_dictionary() * because it can return right away. */ if (!init_string(&path)) return BITTORRENT_STATE_OUT_OF_MEM; state = parse_bencoding_file_dictionary(meta, scanner, &path); done_string(&path); if (state != BITTORRENT_STATE_OK) return state; } return BITTORRENT_STATE_ERROR;}/* Parse the info dictionary which contains file and piece infomation. */static enum bittorrent_stateparse_bencoding_info_dictionary(struct bittorrent_meta *meta, struct scanner *scanner){ struct bittorrent_file file; assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_DICTIONARY); skip_scanner_token(scanner); memset(&file, 0, sizeof(file)); while (scanner_has_tokens(scanner)) { struct scanner_token *value; enum bittorrent_state state; int malicious; off_t length; switch (check_bencoding_dictionary_entry(scanner, &value)) { case BENCODING_TOKEN_NAME: meta->name = normalize_bencoding_path(value->string, value->length, &malicious); if (!meta->name) return BITTORRENT_STATE_OUT_OF_MEM; if (malicious) meta->malicious_paths = malicious; skip_scanner_token(scanner); break; case BENCODING_TOKEN_PIECES: /* The piece hash must be a multiple of the SHA digest * length. */ if ((value->length % SHA_DIGEST_LENGTH) != 0) return BITTORRENT_STATE_ERROR; meta->pieces = value->length / SHA_DIGEST_LENGTH; meta->piece_hash = memacpy(value->string, value->length); skip_scanner_token(scanner); break; case BENCODING_TOKEN_PIECE_LENGTH: length = parse_bencoding_integer(value); if (length < 0 || length >= INT_MAX) return BITTORRENT_STATE_ERROR; meta->piece_length = (uint32_t) length; skip_scanner_token(scanner); break; case BENCODING_TOKEN_FILES: meta->type = BITTORRENT_MULTI_FILE; state = parse_bencoding_files_list(meta, scanner); if (state != BITTORRENT_STATE_OK) return state; break; case BENCODING_TOKEN_LENGTH: file.length = parse_bencoding_integer(value); skip_scanner_token(scanner); break; case BENCODING_TOKEN_MD5SUM: if (value->length != 32) return BITTORRENT_STATE_ERROR; memcpy(file.md5sum, value->string, value->length); skip_scanner_token(scanner); break; case BENCODING_TOKEN_END: /* All file info was saved from the 'files' list. */ if (meta->type == BITTORRENT_MULTI_FILE) return BITTORRENT_STATE_OK; if (!meta->name) return BITTORRENT_STATE_ERROR; return add_bittorrent_file(meta, meta->name, &file); case BENCODING_TOKEN_ERROR: return BITTORRENT_STATE_ERROR; case BENCODING_TOKEN_NONE: default: skip_bencoding_tokens(scanner); } } /* Check if all requirements were met. */ return BITTORRENT_STATE_ERROR;}/* Validate that the bencoded metainfo file contained all the required fields * and that their values are sane. */static enum bittorrent_statecheck_bittorrent_metafile(struct bittorrent_meta *meta){ struct bittorrent_file *file; off_t last_piece_length = 0; off_t total_length = 0; if (bittorrent_id_is_empty(meta->info_hash) || !meta->pieces || !meta->name || !meta->name[0] || !meta->piece_hash || !meta->piece_length || !meta->tracker_uris.size || list_empty(meta->files)) return BITTORRENT_STATE_ERROR; /* FIXME: Should we also check if any two files have the same name? */ foreach (file, meta->files) { if (file->length < 0 || !file->name) return BITTORRENT_STATE_ERROR; total_length += file->length; } last_piece_length = (off_t) total_length % meta->piece_length; if (!last_piece_length) last_piece_length = meta->piece_length; meta->last_piece_length = (uint32_t) last_piece_length; /* Check that the non-zero last_piece_length can be stored. */ if (meta->last_piece_length != last_piece_length) return BITTORRENT_STATE_ERROR; return BITTORRENT_STATE_OK;}enum bittorrent_stateparse_bittorrent_metafile(struct bittorrent_meta *meta, struct string *metafile){ struct scanner scanner; memset(meta, 0, sizeof(*meta)); init_list(meta->files); init_scanner(&scanner, &bencoding_scanner_info, metafile->source, metafile->source + metafile->length); { struct scanner_token *token = get_scanner_token(&scanner); if (!token || token->type != BENCODING_TOKEN_DICTIONARY) return BITTORRENT_STATE_ERROR; skip_scanner_token(&scanner); } while (scanner_has_tokens(&scanner)) { struct scanner_token *value; switch (check_bencoding_dictionary_entry(&scanner, &value)) { case BENCODING_TOKEN_ANNOUNCE: { unsigned char *value_string; struct uri *uri; value_string = memacpy(value->string, value->length); skip_scanner_token(&scanner); if (!value_string) break; uri = get_uri(value_string, 0); mem_free(value_string); if (uri) { add_to_uri_list(&meta->tracker_uris, uri); done_uri(uri); } break; } case BENCODING_TOKEN_ANNOUNCE_LIST: /* FIXME: Add to the tracker URI list, when/if multiple * trackers are/will be supported. */ skip_bencoding_tokens(&scanner); break; case BENCODING_TOKEN_INFO: { unsigned char *start = value->string; struct scanner_token *token; enum bittorrent_state state; state = parse_bencoding_info_dictionary(meta, &scanner); if (state != BITTORRENT_STATE_OK) return BITTORRENT_STATE_ERROR; token = get_scanner_token(&scanner); assert(token && token->type == BENCODING_TOKEN_END); /* Digest the dictionary to create the info hash. */ SHA1(start, token->string + token->length - start, meta->info_hash); skip_scanner_token(&scanner); break; } case BENCODING_TOKEN_COMMENT: meta->comment = memacpy(value->string, int_min(value->length, MAX_STR_LEN)); skip_scanner_token(&scanner); break; case BENCODING_TOKEN_CREATION_DATE: meta->creation_date = (time_t) parse_bencoding_integer(value); skip_scanner_token(&scanner); break; case BENCODING_TOKEN_CREATED_BY: skip_scanner_token(&scanner); break; case BENCODING_TOKEN_END: /* Check if all requirements were met. */ return check_bittorrent_metafile(meta); case BENCODING_TOKEN_ERROR: return BITTORRENT_STATE_ERROR; case BENCODING_TOKEN_NONE: default: skip_bencoding_tokens(&scanner); } } return BITTORRENT_STATE_ERROR;}/* ************************************************************************** *//* Tracker response parsing: *//* ************************************************************************** */static enum bittorrent_stateparse_bencoding_peer_dictionary(struct bittorrent_connection *bittorrent, struct scanner *scanner){ struct scanner_token ip; bittorrent_id_T id; /* Set to invalid value. */ int port = -1; assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_DICTIONARY); skip_scanner_token(scanner); memset(id, 0, sizeof(bittorrent_id_T)); memset(&ip, 0, sizeof(ip)); while (scanner_has_tokens(scanner)) { struct scanner_token *value; switch (check_bencoding_dictionary_entry(scanner, &value)) { case BENCODING_TOKEN_IP: copy_struct(&ip, value); skip_scanner_token(scanner); break; case BENCODING_TOKEN_PORT: port = (int) parse_bencoding_integer(value); skip_scanner_token(scanner); break; case BENCODING_TOKEN_PEER_ID: if (value->length != sizeof(bittorrent_id_T)) return BITTORRENT_STATE_ERROR; memcpy(id, value->string, value->length); skip_scanner_token(scanner); break; case BENCODING_TOKEN_END: skip_scanner_token(scanner); return add_peer_to_bittorrent_pool(bittorrent, id, port, ip.string, ip.length); case BENCODING_TOKEN_ERROR: return BITTORRENT_STATE_ERROR; case BENCODING_TOKEN_NONE: default: skip_bencoding_tokens(scanner); } } return BITTORRENT_STATE_ERROR;}static enum bittorrent_stateparse_bencoding_peers_list(struct bittorrent_connection *bittorrent, struct scanner *scanner){ assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_LIST); skip_scanner_token(scanner); while (scanner_has_tokens(scanner)) { struct scanner_token *token = get_scanner_token(scanner); enum bittorrent_state state; if (!token) break; if (token->type == BENCODING_TOKEN_END) return BITTORRENT_STATE_OK; if (token->type != BENCODING_TOKEN_DICTIONARY) return BITTORRENT_STATE_ERROR; state = parse_bencoding_peer_dictionary(bittorrent, scanner); if (state != BITTORRENT_STATE_OK) return state; } return BITTORRENT_STATE_ERROR;}/* Parses the compact peer list format. It is a string made up of substrings of * length 6, where the first 4 bytes hold the IP address and the 2 last bytes * hold the port number. */static enum bittorrent_stateparse_bencoding_peers_string(struct bittorrent_connection *bittorrent, struct scanner *scanner){ struct scanner_token *token = get_scanner_token(scanner); unsigned char *pos; unsigned char *last_peer_info_start = token->string + token->length - 6; enum bittorrent_state state = BITTORRENT_STATE_OK; assert(get_scanner_token(scanner)->type == BENCODING_TOKEN_STRING); for (pos = token->string; pos <= last_peer_info_start; pos += 6) { /* Only IPv4 strings can occur in this format. */ unsigned char ip[INET_ADDRSTRLEN]; int iplen; uint16_t port; iplen = snprintf(ip, sizeof(ip), "%d.%d.%d.%d", (int) pos[0], (int) pos[1], (int) pos[2], (int) pos[3]); memcpy(&port, pos + 4, sizeof(port)); port = ntohs(port); state = add_peer_to_bittorrent_pool(bittorrent, NULL, port, ip, iplen); if (state != BITTORRENT_STATE_OK) break; } return state;}enum bittorrent_stateparse_bittorrent_tracker_response(struct bittorrent_connection *bittorrent, struct string *response){ struct scanner scanner; init_scanner(&scanner, &bencoding_scanner_info, response->source, response->source + response->length); { struct scanner_token *token = get_scanner_token(&scanner); if (!token || token->type != BENCODING_TOKEN_DICTIONARY) return BITTORRENT_STATE_ERROR; skip_scanner_token(&scanner); } while (scanner_has_tokens(&scanner)) { struct scanner_token *value; enum bittorrent_state state; off_t integer; switch (check_bencoding_dictionary_entry(&scanner, &value)) { case BENCODING_TOKEN_FAILURE_REASON: response->source = value->string; response->length = value->length; return BITTORRENT_STATE_REQUEST_FAILURE; case BENCODING_TOKEN_INTERVAL: bittorrent->tracker.interval = (int) parse_bencoding_integer(value); skip_scanner_token(&scanner); break; case BENCODING_TOKEN_COMPLETE: integer = parse_bencoding_integer(value); if (0 < integer && integer < INT_MAX) bittorrent->complete = (uint32_t) integer; skip_scanner_token(&scanner); break; case BENCODING_TOKEN_INCOMPLETE: integer = parse_bencoding_integer(value); if (0 < integer && integer < INT_MAX) bittorrent->incomplete = (uint32_t) integer; skip_scanner_token(&scanner); break; case BENCODING_TOKEN_PEERS: /* There are two formats: the normal list and the more * compact string variant. */ switch (value->type) { case BENCODING_TOKEN_LIST: state = parse_bencoding_peers_list(bittorrent, &scanner); if (state != BITTORRENT_STATE_OK) return state; assert(get_scanner_token(&scanner) && get_scanner_token(&scanner)->type == BENCODING_TOKEN_END); break; case BENCODING_TOKEN_STRING: /* Parse peer list when using compact format. */ state = parse_bencoding_peers_string(bittorrent, &scanner); if (state != BITTORRENT_STATE_OK) return state; assert(get_scanner_token(&scanner) == value); break; default: return BITTORRENT_STATE_ERROR; } skip_scanner_token(&scanner); break; case BENCODING_TOKEN_END: /* TODO: Check if all requirements were met. */ return BITTORRENT_STATE_OK; case BENCODING_TOKEN_ERROR: return BITTORRENT_STATE_ERROR; case BENCODING_TOKEN_NONE: default: skip_bencoding_tokens(&scanner); } } return BITTORRENT_STATE_ERROR;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?