diff --git a/examples/client_test.cpp b/examples/client_test.cpp index c883809af..84d7009c2 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -842,7 +842,8 @@ int main(int argc, char* argv[]) if (load_file(".ses_state", in) == 0) { lazy_entry e; - if (lazy_bdecode(&in[0], &in[0] + in.size(), e) == 0) + error_code ec; + if (lazy_bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) ses.load_state(e); } diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index 413bc2aa7..f922d4342 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -60,17 +60,18 @@ int main(int argc, char* argv[]) return 1; } lazy_entry e; - ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); + error_code ec; + int pos; + ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec, &pos); if (ret != 0) { - fprintf(stderr, "invalid bencoding: %d\n", ret); + fprintf(stderr, "failed to decode: '%s' at character: %d\n", ec.message().c_str(), pos); return 1; } printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str()); - error_code ec; torrent_info t(e, ec); if (ec) { diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index 08c45544a..fa9f74ac9 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -245,6 +245,23 @@ namespace libtorrent invalid_tracker_response_length, invalid_tracker_transaction_id, invalid_tracker_action, + reserved180, + reserved181, + reserved182, + reserved183, + reserved184, + reserved185, + reserved186, + reserved187, + reserved188, + reserved189, + +// bdecode errors + expected_string, // 190 + expected_colon, + unexpected_eof, + expected_value, + depth_exceeded, error_code_max }; diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index bca6ee227..f7825a363 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/assert.hpp" #include "libtorrent/size_type.hpp" +#include "libtorrent/error_code.hpp" #if TORRENT_USE_IOSTREAM #include @@ -52,7 +53,9 @@ namespace libtorrent TORRENT_EXPORT char const* parse_int(char const* start, char const* end , char delimiter, boost::int64_t& val); // return 0 = success - TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit = 1000); + TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end + , lazy_entry& ret, error_code& ec, int* error_pos = 0 + , int depth_limit = 1000); struct pascal_string { diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 5e54dbf76..7004e103c 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -374,8 +374,11 @@ namespace libtorrent lazy_entry const* info(char const* key) const { if (m_info_dict.type() == lazy_entry::none_t) + { + error_code ec; lazy_bdecode(m_info_section.get(), m_info_section.get() - + m_info_section_size, m_info_dict); + + m_info_section_size, m_info_dict, ec); + } return m_info_dict.dict_find(key); } diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index f14038133..c6f321f60 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1248,7 +1248,9 @@ namespace libtorrent (*m_logger) << time_now_string() << " <== HASHPIECE " << p.piece << " list: " << list_size << " "; #endif lazy_entry hash_list; - if (lazy_bdecode(recv_buffer.begin + 13, recv_buffer.end + 13 + list_size, hash_list) != 0) + error_code ec; + if (lazy_bdecode(recv_buffer.begin + 13, recv_buffer.end + 13 + list_size + , hash_list, ec) != 0) { disconnect(errors::invalid_hash_piece, 2); return; @@ -1518,11 +1520,14 @@ namespace libtorrent buffer::const_interval recv_buffer = receive_buffer(); lazy_entry root; - lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root); + error_code ec; + int pos; + lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos); if (root.type() != lazy_entry::dict_t) { #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " invalid extended handshake\n"; + (*m_logger) << time_now_string() << " invalid extended handshake: " << ec.message() + << "pos: " << pos << "\n"; #endif return; } diff --git a/src/error_code.cpp b/src/error_code.cpp index 8f67a095c..37a771afd 100644 --- a/src/error_code.cpp +++ b/src/error_code.cpp @@ -233,6 +233,23 @@ namespace libtorrent "udp tracker response packet has invalid size", "invalid transaction id in udp tracker response", "invalid action field in udp tracker response", + "", + "", + "", + "", + "", + "", + "", + "", + "", + + +// bdecode errors + "expected string in bdecoded string", + "expected colon in bdecoded string", + "unexpected end of file in bdecoded string", + "expected value (list, dict, int or string) in bencoded string", + "bencoded nesting depth exceeded", }; if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0])) return "Unknown error"; diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index ade7e945a..d2adf53dc 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -301,7 +301,8 @@ namespace libtorrent // handle tracker response lazy_entry e; - int res = lazy_bdecode(data, data + size, e); + error_code ecode; + int res = lazy_bdecode(data, data + size, e, ecode); if (res == 0 && e.type() == lazy_entry::dict_t) { @@ -309,7 +310,7 @@ namespace libtorrent } else { - fail(error_code(errors::invalid_bencoding), parser.status_code()); + fail(ecode, parser.status_code()); } close(); } diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index eb8db07fa..85d3e23d5 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -509,11 +509,14 @@ namespace libtorrent { namespace dht TORRENT_ASSERT(bytes_transferred > 0); lazy_entry e; - int ret = lazy_bdecode(buf, buf + bytes_transferred, e); + int pos; + error_code ec; + int ret = lazy_bdecode(buf, buf + bytes_transferred, e, ec, &pos); if (ret != 0) { #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: Invalid bencoding"; + TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: " + << ec.message() << " pos: " << pos; #endif return; } @@ -615,16 +618,16 @@ namespace libtorrent { namespace dht m_send_buf.clear(); bencode(std::back_inserter(m_send_buf), e); + error_code ec; #ifdef TORRENT_DHT_VERBOSE_LOGGING std::stringstream log_line; lazy_entry print; - int ret = lazy_bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print); + int ret = lazy_bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print, 0, ec); TORRENT_ASSERT(ret == 0); log_line << print_entry(print, true); #endif - error_code ec; if (m_sock.send(addr, &m_send_buf[0], (int)m_send_buf.size(), ec, send_flags)) { if (ec) return false; diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index 023114cfb..d8871b034 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -47,12 +47,14 @@ namespace namespace libtorrent { - int fail_bdecode(lazy_entry& ret, int return_value = -1) - { - ret.clear(); - return return_value; - } +#define TORRENT_FAIL_BDECODE(code) \ + { \ + ec = code; \ + if (error_pos) *error_pos = start - orig_start; \ + ret.clear(); \ + return -1; \ + } // fills in 'val' with what the string between start and the // first occurance of the delimiter is interpreted as an int. // return the pointer to the delimiter, or 0 if there is a @@ -76,8 +78,10 @@ namespace libtorrent } // return 0 = success - int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit) + int lazy_bdecode(char const* start, char const* end, lazy_entry& ret + , error_code& ec, int* error_pos, int depth_limit) { + char const* const orig_start = start; ret.clear(); if (start == end) return 0; @@ -90,11 +94,11 @@ namespace libtorrent lazy_entry* top = stack.back(); - if (int(stack.size()) > depth_limit) return fail_bdecode(ret); - if (start >= end) return fail_bdecode(ret); + if (int(stack.size()) > depth_limit) TORRENT_FAIL_BDECODE(errors::depth_exceeded); + if (start >= end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); char t = *start; ++start; - if (start >= end && t != 'e') return fail_bdecode(ret); + if (start >= end && t != 'e') TORRENT_FAIL_BDECODE(errors::unexpected_eof); switch (top->type()) { @@ -106,16 +110,17 @@ namespace libtorrent stack.pop_back(); continue; } - if (!is_digit(t)) return fail_bdecode(ret); + if (!is_digit(t)) TORRENT_FAIL_BDECODE(errors::expected_string); boost::int64_t len = t - '0'; start = parse_int(start, end, ':', len); - if (start == 0 || start + len + 3 > end || *start != ':') return fail_bdecode(ret); + if (start == 0 || start + len + 3 > end || *start != ':') + TORRENT_FAIL_BDECODE(errors::expected_colon); ++start; - if (start == end) return fail_bdecode(ret); + if (start == end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); lazy_entry* ent = top->dict_append(start); - if (ent == 0) return fail_bdecode(ret, -2); + if (ent == 0) TORRENT_FAIL_BDECODE(errors::no_memory); start += len; - if (start >= end) return fail_bdecode(ret); + if (start >= end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); stack.push_back(ent); t = *start; ++start; @@ -130,7 +135,7 @@ namespace libtorrent continue; } lazy_entry* ent = top->list_append(); - if (ent == 0) return fail_bdecode(ret, -2); + if (ent == 0) TORRENT_FAIL_BDECODE(errors::no_memory); stack.push_back(ent); break; } @@ -151,7 +156,7 @@ namespace libtorrent char const* int_start = start; start = find_char(start, end, 'e'); top->construct_int(int_start, start - int_start); - if (start == end) return fail_bdecode(ret); + if (start == end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); TORRENT_ASSERT(*start == 'e'); ++start; stack.pop_back(); @@ -159,11 +164,12 @@ namespace libtorrent } default: { - if (!is_digit(t)) return fail_bdecode(ret); + if (!is_digit(t)) TORRENT_FAIL_BDECODE(errors::expected_value); boost::int64_t len = t - '0'; start = parse_int(start, end, ':', len); - if (start == 0 || start + len + 1 > end || *start != ':') return fail_bdecode(ret); + if (start == 0 || start + len + 1 > end || *start != ':') + TORRENT_FAIL_BDECODE(errors::expected_colon); ++start; top->construct_string(start, int(len)); stack.pop_back(); diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp index 6bb490757..446f83652 100644 --- a/src/lt_trackers.cpp +++ b/src/lt_trackers.cpp @@ -191,7 +191,8 @@ namespace libtorrent { namespace if (!m_pc.packet_finished()) return true; lazy_entry msg; - int ret = lazy_bdecode(body.begin, body.end, msg); + error_code ec; + int ret = lazy_bdecode(body.begin, body.end, msg, ec); if (ret != 0 || msg.type() != lazy_entry::dict_t) { m_pc.disconnect(errors::invalid_lt_tracker_message, 2); diff --git a/src/session.cpp b/src/session.cpp index a8638ed5c..e02100742 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -407,7 +407,8 @@ namespace libtorrent std::vector buf; bencode(std::back_inserter(buf), ses_state); lazy_entry e; - lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); + error_code ec; + lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec); TORRENT_SYNC_CALL1(load_state, &e); } diff --git a/src/torrent.cpp b/src/torrent.cpp index ec4d7045c..af9ef5ed9 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -445,18 +445,20 @@ namespace libtorrent if (!m_resume_data.empty()) { + int pos; + error_code ec; if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0] - + m_resume_data.size(), m_resume_entry) != 0) + + m_resume_data.size(), m_resume_entry, ec, &pos) != 0) { std::vector().swap(m_resume_data); +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + (*m_ses.m_logger) << time_now_string() << " fastresume data for " + << torrent_file().name() << " rejected: " << ec.message() + << " pos: " << pos << "\n"; +#endif if (m_ses.m_alerts.should_post()) { - error_code ec(errors::parse_failed); m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), ec)); -#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING - (*m_ses.m_logger) << time_now_string() << " fastresume data for " - << torrent_file().name() << " rejected: " << ec.message() << "\n"; -#endif } } } @@ -4474,8 +4476,8 @@ namespace libtorrent } lazy_entry metadata; - int ret = lazy_bdecode(metadata_buf, metadata_buf + metadata_size, metadata); error_code ec; + int ret = lazy_bdecode(metadata_buf, metadata_buf + metadata_size, metadata, ec); if (ret != 0 || !m_torrent_file->parse_info_section(metadata, ec)) { // this means the metadata is correct, since we @@ -4483,6 +4485,7 @@ namespace libtorrent // failed to parse it. Pause the torrent if (alerts().should_post()) { + // TODO: pass in ec along with the alert alerts().post_alert(metadata_failed_alert(get_handle())); } set_error(errors::invalid_swarm_metadata, ""); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index a11c8033c..57039f37b 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -456,10 +456,11 @@ namespace libtorrent { if (m_info_section_size > 0) { + error_code ec; m_info_section.reset(new char[m_info_section_size]); memcpy(m_info_section.get(), t.m_info_section.get(), m_info_section_size); int ret = lazy_bdecode(m_info_section.get(), m_info_section.get() - + m_info_section_size, m_info_dict); + + m_info_section_size, m_info_dict, ec); lazy_entry const* pieces = m_info_dict.dict_find_string("pieces"); if (pieces && pieces->string_length() == m_files.num_pieces() * 20) @@ -498,14 +499,14 @@ namespace libtorrent bencode(out, torrent_file); lazy_entry e; - if (lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e) != 0) + error_code ec; + if (lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0) { #ifndef BOOST_NO_EXCEPTIONS throw invalid_torrent_file(errors::invalid_bencoding); #endif return; } - error_code ec; #ifndef BOOST_NO_EXCEPTIONS if (!parse_torrent_file(e, ec)) throw invalid_torrent_file(ec); @@ -541,8 +542,8 @@ namespace libtorrent { error_code ec; lazy_entry e; - if (lazy_bdecode(buffer, buffer + size, e) != 0) - throw invalid_torrent_file(errors::invalid_bencoding); + if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) + throw invalid_torrent_file(ec); if (!parse_torrent_file(e, ec)) throw invalid_torrent_file(ec); @@ -561,9 +562,10 @@ namespace libtorrent if (ret < 0) return; lazy_entry e; - if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0) - throw invalid_torrent_file(errors::invalid_bencoding); error_code ec; + if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + throw invalid_torrent_file(ec); + if (!parse_torrent_file(e, ec)) throw invalid_torrent_file(ec); } @@ -585,10 +587,10 @@ namespace libtorrent if (ret < 0) return; lazy_entry e; - if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0) - throw invalid_torrent_file(errors::invalid_bencoding); - error_code ec; + if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + throw invalid_torrent_file(ec); + if (!parse_torrent_file(e, ec)) throw invalid_torrent_file(ec); } @@ -616,11 +618,8 @@ namespace libtorrent , m_i2p(false) { lazy_entry e; - if (lazy_bdecode(buffer, buffer + size, e) != 0) - { - ec = errors::invalid_bencoding; + if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) return; - } parse_torrent_file(e, ec); } @@ -637,11 +636,8 @@ namespace libtorrent if (ret < 0) return; lazy_entry e; - if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0) - { - ec = errors::invalid_bencoding; + if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) return; - } parse_torrent_file(e, ec); } @@ -661,11 +657,8 @@ namespace libtorrent if (ret < 0) return; lazy_entry e; - if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0) - { - ec = errors::invalid_bencoding; + if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) return; - } parse_torrent_file(e, ec); } #endif diff --git a/src/ut_pex.cpp b/src/ut_pex.cpp index f7df55468..e1cfb4257 100644 --- a/src/ut_pex.cpp +++ b/src/ut_pex.cpp @@ -243,7 +243,8 @@ namespace libtorrent { namespace if (body.left() < length) return true; lazy_entry pex_msg; - int ret = lazy_bdecode(body.begin, body.end, pex_msg); + error_code ec; + int ret = lazy_bdecode(body.begin, body.end, pex_msg, ec); if (ret != 0 || pex_msg.type() != lazy_entry::dict_t) { m_pc.disconnect(errors::invalid_pex_message, 2); diff --git a/test/test_bdecode_performance.cpp b/test/test_bdecode_performance.cpp index ec608425f..b726bdd77 100644 --- a/test/test_bdecode_performance.cpp +++ b/test/test_bdecode_performance.cpp @@ -17,7 +17,8 @@ int test_main() { char b[] = "d1:ai12453e1:b3:aaa1:c3:bbbe"; lazy_entry e; - int ret = lazy_bdecode(b, b + sizeof(b)-1, e); + error_code ec; + int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec); } ptime stop(time_now()); diff --git a/test/test_bencoding.cpp b/test/test_bencoding.cpp index 6d9956404..d51841754 100644 --- a/test/test_bencoding.cpp +++ b/test/test_bencoding.cpp @@ -107,7 +107,8 @@ int test_main() { char b[] = "i12453e"; lazy_entry e; - int ret = lazy_bdecode(b, b + sizeof(b)-1, e); + error_code ec; + int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec); TORRENT_ASSERT(ret == 0); #if TORRENT_USE_IOSTREAM std::cout << e << std::endl; @@ -122,7 +123,8 @@ int test_main() { char b[] = "26:abcdefghijklmnopqrstuvwxyz"; lazy_entry e; - int ret = lazy_bdecode(b, b + sizeof(b)-1, e); + error_code ec; + int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec); TORRENT_ASSERT(ret == 0); #if TORRENT_USE_IOSTREAM std::cout << e << std::endl; @@ -138,7 +140,8 @@ int test_main() { char b[] = "li12453e3:aaae"; lazy_entry e; - int ret = lazy_bdecode(b, b + sizeof(b)-1, e); + error_code ec; + int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec); TORRENT_ASSERT(ret == 0); #if TORRENT_USE_IOSTREAM std::cout << e << std::endl; @@ -161,7 +164,8 @@ int test_main() { char b[] = "d1:ai12453e1:b3:aaa1:c3:bbb1:X10:0123456789e"; lazy_entry e; - int ret = lazy_bdecode(b, b + sizeof(b)-1, e); + error_code ec; + int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec); TORRENT_ASSERT(ret == 0); #if TORRENT_USE_IOSTREAM std::cout << e << std::endl; @@ -201,7 +205,8 @@ int test_main() printf("%s\n", buf); lazy_entry e; - int ret = lazy_bdecode(buf, buf + sizeof(buf), e); + error_code ec; + int ret = lazy_bdecode(buf, buf + sizeof(buf), e, ec); TEST_CHECK(ret == -1); } return 0; diff --git a/test/test_dht.cpp b/test/test_dht.cpp index eef838198..5be74d80c 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -66,7 +66,7 @@ void send_dht_msg(datagram_socket& sock, char const* msg, lazy_entry* reply, cha TEST_CHECK(!ec); if (ec) std::cout << ec.message() << std::endl; - int ret = lazy_bdecode(inbuf, inbuf + size, *reply); + int ret = lazy_bdecode(inbuf, inbuf + size, *reply, ec); TEST_CHECK(ret == 0); } diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 88c1f98a4..d689af304 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -462,7 +462,7 @@ int test_main() std::vector buf; bencode(std::back_inserter(buf), session_state); lazy_entry session_state2; - ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), session_state2); + ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), session_state2, ec); TEST_CHECK(ret == 0); fprintf(stderr, "session_state\n%s\n", print_entry(session_state2).c_str());