void do_handshake(tcp::socket& s, sha1_hash const& ih, char* buffer) { char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\x10\0\x04" " " // space for info-hash "aaaaaaaaaaaaaaaaaaaa"; // peer-id log("==> handshake"); error_code ec; std::memcpy(handshake + 28, ih.begin(), 20); boost::asio::write(s, boost::asio::buffer(handshake, sizeof(handshake) - 1) , boost::asio::transfer_all(), ec); if (ec) { TEST_ERROR(ec.message()); return; } // read handshake boost::asio::read(s, boost::asio::buffer(buffer, 68) , boost::asio::transfer_all(), ec); if (ec) { TEST_ERROR(ec.message()); return; } log("<== handshake"); TEST_CHECK(buffer[0] == 19); TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0); char* extensions = buffer + 20; // check for fast extension support TEST_CHECK(extensions[7] & 0x4); // check for extension protocol support bool const lt_extension_protocol = (extensions[5] & 0x10) != 0; #ifndef TORRENT_DISABLE_EXTENSIONS TEST_CHECK(lt_extension_protocol == true); #else TEST_CHECK(lt_extension_protocol == false); #endif // check for DHT support bool const dht_support = (extensions[7] & 0x1) != 0; #ifndef TORRENT_DISABLE_DHT TEST_CHECK(dht_support == true); #else TEST_CHECK(dht_support == false); #endif TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0); }
void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer) { char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04" " " // space for info-hash "aaaaaaaaaaaaaaaaaaaa" // peer-id "\0\0\0\x01\x0e"; // have_all std::cout << "send handshake" << std::endl; error_code ec; std::memcpy(handshake + 28, ih.begin(), 20); libtorrent::asio::write(s, libtorrent::asio::buffer(handshake, sizeof(handshake) - 1), libtorrent::asio::transfer_all(), ec); if (ec) { std::cout << ec.message() << std::endl; exit(1); } // read handshake libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 68), libtorrent::asio::transfer_all(), ec); if (ec) { std::cout << ec.message() << std::endl; exit(1); } std::cout << "received handshake" << std::endl; TEST_CHECK(buffer[0] == 19); TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0); char* extensions = buffer + 20; // check for fast extension support TEST_CHECK(extensions[7] & 0x4); #ifndef TORRENT_DISABLE_EXTENSIONS // check for extension protocol support TEST_CHECK(extensions[5] & 0x10); #endif #ifndef TORRENT_DISABLE_DHT // check for DHT support TEST_CHECK(extensions[7] & 0x1); #endif TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0); }
hasher& update(std::string const& data) { update(data.c_str(), data.size()); return *this; } hasher& update(const char* data, int len) { TORRENT_ASSERT(data != 0); TORRENT_ASSERT(len > 0); #ifdef TORRENT_USE_GCRYPT gcry_md_write(m_context, data, len); #else SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len); #endif return *this; } sha1_hash final() { sha1_hash digest; #ifdef TORRENT_USE_GCRYPT gcry_md_final(m_context); digest.assign((const char*)gcry_md_read(m_context, 0)); #else SHA1_Final(digest.begin(), &m_context); #endif return digest; } void reset() { #ifdef TORRENT_USE_GCRYPT gcry_md_reset(m_context); #else SHA1_Init(&m_context);
bytes sha1_hash_bytes(const sha1_hash& bn) { return bytes(bn.to_string()); }
gcry_md_write(m_context, data.data(), data.size()); #elif TORRENT_USE_COMMONCRYPTO CC_SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data.data()), CC_LONG(data.size())); #elif TORRENT_USE_CRYPTOAPI m_context.update(data); #elif defined TORRENT_USE_LIBCRYPTO SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data.data()), data.size()); #else SHA1_update(&m_context, reinterpret_cast<unsigned char const*>(data.data()), data.size()); #endif return *this; } sha1_hash hasher::final() { sha1_hash digest; #ifdef TORRENT_USE_LIBGCRYPT gcry_md_final(m_context); digest.assign((char const*)gcry_md_read(m_context, 0)); #elif TORRENT_USE_COMMONCRYPTO CC_SHA1_Final(reinterpret_cast<unsigned char*>(digest.data()), &m_context); #elif TORRENT_USE_CRYPTOAPI m_context.get_hash(digest.data(), digest.size()); #elif defined TORRENT_USE_LIBCRYPTO SHA1_Final(reinterpret_cast<unsigned char*>(digest.data()), &m_context); #else SHA1_final(reinterpret_cast<unsigned char*>(digest.data()), &m_context); #endif return digest; }
tracker_response parse_tracker_response(char const* data, int size, error_code& ec , int flags, sha1_hash scrape_ih) { tracker_response resp; bdecode_node e; int res = bdecode(data, data + size, e, ec); if (ec) return resp; if (res != 0 || e.type() != bdecode_node::dict_t) { ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); return resp; } int interval = int(e.dict_find_int_value("interval", 0)); // if no interval is specified, default to 30 minutes if (interval == 0) interval = 1800; int min_interval = int(e.dict_find_int_value("min interval", 30)); resp.interval = interval; resp.min_interval = min_interval; bdecode_node tracker_id = e.dict_find_string("tracker id"); if (tracker_id) resp.trackerid = tracker_id.string_value(); // parse the response bdecode_node failure = e.dict_find_string("failure reason"); if (failure) { resp.failure_reason = failure.string_value(); ec.assign(errors::tracker_failure, get_libtorrent_category()); return resp; } bdecode_node warning = e.dict_find_string("warning message"); if (warning) resp.warning_message = warning.string_value(); if (0 != (flags & tracker_request::scrape_request)) { bdecode_node files = e.dict_find_dict("files"); if (!files) { ec.assign(errors::invalid_files_entry, get_libtorrent_category()); return resp; } bdecode_node scrape_data = files.dict_find_dict( scrape_ih.to_string()); if (!scrape_data) { ec.assign(errors::invalid_hash_entry, get_libtorrent_category()); return resp; } resp.complete = int(scrape_data.dict_find_int_value("complete", -1)); resp.incomplete = int(scrape_data.dict_find_int_value("incomplete", -1)); resp.downloaded = int(scrape_data.dict_find_int_value("downloaded", -1)); resp.downloaders = int(scrape_data.dict_find_int_value("downloaders", -1)); return resp; } // look for optional scrape info resp.complete = int(e.dict_find_int_value("complete", -1)); resp.incomplete = int(e.dict_find_int_value("incomplete", -1)); resp.downloaded = int(e.dict_find_int_value("downloaded", -1)); bdecode_node peers_ent = e.dict_find("peers"); if (peers_ent && peers_ent.type() == bdecode_node::string_t) { char const* peers = peers_ent.string_ptr(); int len = peers_ent.string_length(); #if TORRENT_USE_I2P if (0 != (flags & tracker_request::i2p)) { error_code parse_error; for (int i = 0; i < len; i += 32) { if (len - i < 32) break; peer_entry p; p.hostname = base32encode(std::string(peers + i, 32), string::i2p); p.hostname += ".b32.i2p"; p.port = 6881; resp.peers.push_back(p); } } else #endif { resp.peers4.reserve(len / 6); for (int i = 0; i < len; i += 6) { if (len - i < 6) break; ipv4_peer_entry p; p.ip = detail::read_v4_address(peers).to_v4().to_bytes(); p.port = detail::read_uint16(peers); resp.peers4.push_back(p); } } } else if (peers_ent && peers_ent.type() == bdecode_node::list_t) { int len = peers_ent.list_size(); resp.peers.reserve(len); error_code parse_error; for (int i = 0; i < len; ++i) { peer_entry p; if (!extract_peer_info(peers_ent.list_at(i), p, parse_error)) continue; resp.peers.push_back(p); } // only report an error if all peer entries are invalid if (resp.peers.empty() && parse_error) { ec = parse_error; return resp; } } else { peers_ent.clear(); } #if TORRENT_USE_IPV6 bdecode_node ipv6_peers = e.dict_find_string("peers6"); if (ipv6_peers) { char const* peers = ipv6_peers.string_ptr(); int len = ipv6_peers.string_length(); resp.peers6.reserve(len / 18); for (int i = 0; i < len; i += 18) { if (len - i < 18) break; ipv6_peer_entry p; p.ip = detail::read_v6_address(peers).to_v6().to_bytes(); p.port = detail::read_uint16(peers); resp.peers6.push_back(p); } } else { ipv6_peers.clear(); } #else bdecode_node ipv6_peers; #endif /* // if we didn't receive any peers. We don't care if we're stopping anyway if (peers_ent == 0 && ipv6_peers == 0 && tracker_req().event != tracker_request::stopped) { ec.assign(errors::invalid_peers_entry, get_libtorrent_category()); return resp; } */ bdecode_node ip_ent = e.dict_find_string("external ip"); if (ip_ent) { char const* p = ip_ent.string_ptr(); if (ip_ent.string_length() == int(address_v4::bytes_type().size())) resp.external_ip = detail::read_v4_address(p); #if TORRENT_USE_IPV6 else if (ip_ent.string_length() == int(address_v6::bytes_type().size())) resp.external_ip = detail::read_v6_address(p); #endif } return resp; }
tracker_response parse_tracker_response(char const* data, int size, error_code& ec , bool scrape_request, sha1_hash scrape_ih) { tracker_response resp; lazy_entry e; int res = lazy_bdecode(data, data + size, e, ec); if (ec) return resp; if (res != 0 || e.type() != lazy_entry::dict_t) { ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); return resp; } int interval = int(e.dict_find_int_value("interval", 0)); // if no interval is specified, default to 30 minutes if (interval == 0) interval = 1800; int min_interval = int(e.dict_find_int_value("min interval", 30)); resp.interval = interval; resp.min_interval = min_interval; lazy_entry const* tracker_id = e.dict_find_string("tracker id"); if (tracker_id) resp.trackerid = tracker_id->string_value(); // parse the response lazy_entry const* failure = e.dict_find_string("failure reason"); if (failure) { resp.failure_reason = failure->string_value(); ec.assign(errors::tracker_failure, get_libtorrent_category()); return resp; } lazy_entry const* warning = e.dict_find_string("warning message"); if (warning) resp.warning_message = warning->string_value(); if (scrape_request) { lazy_entry const* files = e.dict_find_dict("files"); if (files == 0) { ec.assign(errors::invalid_files_entry, get_libtorrent_category()); return resp; } lazy_entry const* scrape_data = files->dict_find_dict( scrape_ih.to_string()); if (scrape_data == 0) { ec.assign(errors::invalid_hash_entry, get_libtorrent_category()); return resp; } resp.complete = int(scrape_data->dict_find_int_value("complete", -1)); resp.incomplete = int(scrape_data->dict_find_int_value("incomplete", -1)); resp.downloaded = int(scrape_data->dict_find_int_value("downloaded", -1)); resp.downloaders = int(scrape_data->dict_find_int_value("downloaders", -1)); return resp; } // look for optional scrape info resp.complete = int(e.dict_find_int_value("complete", -1)); resp.incomplete = int(e.dict_find_int_value("incomplete", -1)); resp.downloaded = int(e.dict_find_int_value("downloaded", -1)); lazy_entry const* peers_ent = e.dict_find("peers"); if (peers_ent && peers_ent->type() == lazy_entry::string_t) { char const* peers = peers_ent->string_ptr(); int len = peers_ent->string_length(); resp.peers4.reserve(len / 6); for (int i = 0; i < len; i += 6) { if (len - i < 6) break; ipv4_peer_entry p; error_code ec; p.ip = detail::read_v4_address(peers).to_v4().to_bytes(); p.port = detail::read_uint16(peers); resp.peers4.push_back(p); } } else if (peers_ent && peers_ent->type() == lazy_entry::list_t) { int len = peers_ent->list_size(); resp.peers.reserve(len); error_code parse_error; for (int i = 0; i < len; ++i) { peer_entry p; if (!extract_peer_info(*peers_ent->list_at(i), p, parse_error)) continue; resp.peers.push_back(p); } // only report an error if all peer entries are invalid if (resp.peers.empty() && parse_error) { ec = parse_error; return resp; } } else { peers_ent = 0; } #if TORRENT_USE_IPV6 lazy_entry const* ipv6_peers = e.dict_find_string("peers6"); if (ipv6_peers) { char const* peers = ipv6_peers->string_ptr(); int len = ipv6_peers->string_length(); resp.peers6.reserve(len / 18); for (int i = 0; i < len; i += 18) { if (len - i < 18) break; ipv6_peer_entry p; p.ip = detail::read_v6_address(peers).to_v6().to_bytes(); p.port = detail::read_uint16(peers); resp.peers6.push_back(p); } } else { ipv6_peers = 0; } #else lazy_entry const* ipv6_peers = 0; #endif /* // if we didn't receive any peers. We don't care if we're stopping anyway if (peers_ent == 0 && ipv6_peers == 0 && tracker_req().event != tracker_request::stopped) { ec.assign(errors::invalid_peers_entry, get_libtorrent_category()); return resp; } */ lazy_entry const* ip_ent = e.dict_find_string("external ip"); if (ip_ent) { char const* p = ip_ent->string_ptr(); if (ip_ent->string_length() == int(address_v4::bytes_type().size())) resp.external_ip = detail::read_v4_address(p); #if TORRENT_USE_IPV6 else if (ip_ent->string_length() == int(address_v6::bytes_type().size())) resp.external_ip = detail::read_v6_address(p); #endif } return resp; }
bool is_valid() const { return !t_hash.is_all_zeros() && !peer_id.is_all_zeros(); }