Esempio n. 1
0
	// convert a bdecode_node into an old skool entry
	void entry::operator=(bdecode_node const& e)
	{
		switch (e.type())
		{
			case bdecode_node::string_t:
				this->string() = e.string_value();
				break;
			case bdecode_node::int_t:
				this->integer() = e.int_value();
				break;
			case bdecode_node::dict_t:
			{
				dictionary_type& d = this->dict();
				for (int i = 0; i < e.dict_size(); ++i)
				{
					std::pair<std::string, bdecode_node> elem = e.dict_at(i);
					d[elem.first] = elem.second;
				}
				break;
			}
			case bdecode_node::list_t:
			{
				list_type& l = this->list();
				for (int i = 0; i < e.list_size(); ++i)
				{
					l.push_back(entry());
					l.back() = e.list_at(i);
				}
				break;
			}
			case bdecode_node::none_t:
				destruct();
				break;
		}
	}
Esempio n. 2
0
	void on_read(lt::error_code const& ec, std::size_t bytes_transferred)
	{
		if (ec) return;

		using libtorrent::entry;
		using libtorrent::bdecode;

		int pos;
		error_code err;

		// since the simulation is single threaded, we can get away with just
		// allocating a single of these
		static bdecode_node msg;
		int ret = bdecode(m_buffer, m_buffer + bytes_transferred, msg, err, &pos, 10, 500);
		if (ret != 0) return;

		if (msg.type() != bdecode_node::dict_t) return;

		libtorrent::dht::msg m(msg, m_ep);
		dht().incoming(m);

		sock().async_receive_from(asio::mutable_buffers_1(m_buffer, sizeof(m_buffer))
			, m_ep, [&](lt::error_code const& ec, std::size_t bytes_transferred)
				{ this->on_read(ec, bytes_transferred); });
	}
Esempio n. 3
0
void render_variant(std::string& out, bdecode_node const& e)
{
	switch (e.type())
	{
		case bdecode_node::dict_t:
			print_dict(out);
			for (int i = 0; i < e.dict_size(); ++i)
			{
				std::pair<lt::string_view, bdecode_node> item = e.dict_at(i);
				const bool duplicate = g_seed == 1;
				const bool skipped = g_seed == 2;
				g_seed -= 2;
				if (duplicate)
				{
					print_string(out, item.first.to_string());
					render_variant(out, item.second);
				}
				if (!skipped)
				{
					print_string(out, item.first.to_string());
					render_variant(out, item.second);
				}

				render_arbitrary_item(out);
			}
			print_terminate(out);
			break;
		case bdecode_node::list_t:
			print_list(out);
			for (int i = 0; i < e.list_size(); ++i)
			{
				const bool duplicate = g_seed == 1;
				const bool skipped = g_seed == 2;
				g_seed -= 2;
				if (duplicate) render_variant(out, e.list_at(i));

				render_arbitrary_item(out);

				if (!skipped) render_variant(out, e.list_at(i));
			}
			print_terminate(out);
			break;
		case bdecode_node::int_t:
			print_int(out, e.int_value());
			break;
		case bdecode_node::string_t:
			print_string(out, e.string_value().to_string());
			break;
		default:
			abort();
	}
}
	// root_dir is the name of the torrent, unless this is a single file
	// torrent, in which case it's empty.
	bool extract_files(bdecode_node const& list, file_storage& target
		, std::string const& root_dir, ptrdiff_t info_ptr_diff, error_code& ec)
	{
		if (list.type() != bdecode_node::list_t)
		{
			ec = errors::torrent_file_parse_failed;
			return false;
		}
		target.reserve(list.list_size());

		// this is the counter used to name pad files
		int pad_file_cnt = 0;
		for (int i = 0, end(list.list_size()); i < end; ++i)
		{
			if (!extract_single_file(list.list_at(i), target, root_dir
				, info_ptr_diff, false, pad_file_cnt, ec))
				return false;
		}
		return true;
	}
// TODO: 2 returning a bool here is redundant. Instead this function should
// return the peer_entry
bool extract_peer_info(bdecode_node const& info, peer_entry& ret, error_code& ec)
{
    // extract peer id (if any)
    if (info.type() != bdecode_node::dict_t)
    {
        ec.assign(errors::invalid_peer_dict, get_libtorrent_category());
        return false;
    }
    bdecode_node i = info.dict_find_string("peer id");
    if (i && i.string_length() == 20)
    {
        std::copy(i.string_ptr(), i.string_ptr()+20, ret.pid.begin());
    }
    else
    {
        // if there's no peer_id, just initialize it to a bunch of zeroes
        std::fill_n(ret.pid.begin(), 20, 0);
    }

    // extract ip
    i = info.dict_find_string("ip");
    if (i == 0)
    {
        ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
        return false;
    }
    ret.hostname = i.string_value();

    // extract port
    i = info.dict_find_int("port");
    if (i == 0)
    {
        ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
        return false;
    }
    ret.port = boost::uint16_t(i.int_value());

    return true;
}
Esempio n. 6
0
	std::string print_entry(bdecode_node const& e
		, bool single_line, int indent)
	{
		char indent_str[200];
		using std::memset;
		memset(indent_str, ' ', 200);
		indent_str[0] = ',';
		indent_str[1] = '\n';
		indent_str[199] = 0;
		if (indent < 197 && indent >= 0) indent_str[indent+2] = 0;
		std::string ret;
		switch (e.type())
		{
			case bdecode_node::none_t: return "none";
			case bdecode_node::int_t:
			{
				char str[100];
				snprintf(str, sizeof(str), "%" PRId64, e.int_value());
				return str;
			}
			case bdecode_node::string_t:
			{
				print_string(ret, e.string_ptr(), e.string_length(), single_line);
				return ret;
			}
			case bdecode_node::list_t:
			{
				ret += '[';
				bool one_liner = line_longer_than(e, 200) != -1 || single_line;

				if (!one_liner) ret += indent_str + 1;
				for (int i = 0; i < e.list_size(); ++i)
				{
					if (i == 0 && one_liner) ret += " ";
					ret += print_entry(e.list_at(i), single_line, indent + 2);
					if (i < e.list_size() - 1) ret += (one_liner?", ":indent_str);
					else ret += (one_liner?" ":indent_str+1);
				}
				ret += "]";
				return ret;
			}
			case bdecode_node::dict_t:
			{
				ret += "{";
				bool one_liner = line_longer_than(e, 200) != -1 || single_line;

				if (!one_liner) ret += indent_str+1;
				for (int i = 0; i < e.dict_size(); ++i)
				{
					if (i == 0 && one_liner) ret += " ";
					std::pair<std::string, bdecode_node> ent = e.dict_at(i);
					print_string(ret, ent.first.c_str(), ent.first.size(), true);
					ret += ": ";
					ret += print_entry(ent.second, single_line, indent + 2);
					if (i < e.dict_size() - 1) ret += (one_liner?", ":indent_str);
					else ret += (one_liner?" ":indent_str+1);
				}
				ret += "}";
				return ret;
			}
		}
		return ret;
	}
	// 'top_level' is extracting the file for a single-file torrent. The
	// distinction is that the filename is found in "name" rather than
	// "path"
	// root_dir is the name of the torrent, unless this is a single file
	// torrent, in which case it's empty.
	bool extract_single_file(bdecode_node const& dict, file_storage& files
		, std::string const& root_dir, ptrdiff_t info_ptr_diff, bool top_level
		, int& pad_file_cnt, error_code& ec)
	{
		if (dict.type() != bdecode_node::dict_t) return false;

		boost::uint32_t file_flags = get_file_attributes(dict);

		// symlinks have an implied "size" of zero. i.e. they use up 0 bytes of
		// the torrent payload space
		boost::int64_t const file_size = (file_flags & file_storage::flag_symlink)
			? 0
			: dict.dict_find_int_value("length", -1);
		if (file_size < 0 )
		{
			ec = errors::torrent_invalid_length;
			return false;
		}

		boost::int64_t const mtime = dict.dict_find_int_value("mtime", 0);

		std::string path = root_dir;
		std::string path_element;
		char const* filename = NULL;
		int filename_len = 0;

		if (top_level)
		{
			// prefer the name.utf-8 because if it exists, it is more likely to be
			// correctly encoded
			bdecode_node p = dict.dict_find_string("name.utf-8");
			if (!p) p = dict.dict_find_string("name");
			if (!p || p.string_length() == 0)
			{
				ec = errors::torrent_missing_name;
				return false;
			}

			filename = p.string_ptr() + info_ptr_diff;
			filename_len = p.string_length();
			while (filename_len > 0 && filename[0] == TORRENT_SEPARATOR)
			{
				filename += 1;
				filename_len -= 1;
			}
			sanitize_append_path_element(path, p.string_ptr(), p.string_length());
		}
		else
		{
			bdecode_node p = dict.dict_find_list("path.utf-8");
			if (!p) p = dict.dict_find_list("path");

			if (p && p.list_size() > 0)
			{
				std::size_t const orig_path_len = path.size();
				int const preallocate = path.size() + path_length(p, ec);
				if (ec) return false;
				path.reserve(preallocate);

				for (int i = 0, end(p.list_size()); i < end; ++i)
				{
					bdecode_node e = p.list_at(i);
					if (i == end - 1)
					{
						filename = e.string_ptr() + info_ptr_diff;
						filename_len = e.string_length();
					}
					while (filename_len > 0 && filename[0] == TORRENT_SEPARATOR)
					{
						filename += 1;
						filename_len -= 1;
					}
					sanitize_append_path_element(path, e.string_ptr(), e.string_length());
				}

				// if all path elements were sanitized away, we need to use another
				// name instead
				if (path.size() == orig_path_len)
				{
					path += TORRENT_SEPARATOR;
					path += "_";
				}
			}
			else if (file_flags & file_storage::flag_pad_file)
			{
				// pad files don't need a path element, we'll just store them
				// under the .pad directory
				char cnt[10];
				snprintf(cnt, sizeof(cnt), "%d", pad_file_cnt);
				path = combine_path(".pad", cnt);
				++pad_file_cnt;
			}
			else
			{
				ec = errors::torrent_missing_name;
				return false;
			}
		}

		// bitcomet pad file
		if (path.find("_____padding_file_") != std::string::npos)
			file_flags = file_storage::flag_pad_file;

		bdecode_node fh = dict.dict_find_string("sha1");
		char const* filehash = NULL;
		if (fh && fh.string_length() == 20)
			filehash = fh.string_ptr() + info_ptr_diff;

		std::string symlink_path;
		if (file_flags & file_storage::flag_symlink)
		{
			if (bdecode_node s_p = dict.dict_find_list("symlink path"))
			{
				int const preallocate = path_length(s_p, ec);
				if (ec) return false;
				symlink_path.reserve(preallocate);
				for (int i = 0, end(s_p.list_size()); i < end; ++i)
				{
					bdecode_node const& n = s_p.list_at(i);
					sanitize_append_path_element(symlink_path, n.string_ptr()
						, n.string_length());
				}
			}
		}
		else
		{
			file_flags &= ~file_storage::flag_symlink;
		}

		if (filename_len > path.length()
			|| path.compare(path.size() - filename_len, filename_len, filename
				, filename_len) != 0)
		{
			// if the filename was sanitized and differ, clear it to just use path
			filename = NULL;
			filename_len = 0;
		}

		files.add_file_borrow(filename, filename_len, path, file_size, file_flags, filehash
			, mtime, symlink_path);
		return true;
	}