void http_tracker_connection::parse(int status_code, lazy_entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		int interval = int(e.dict_find_int_value("interval", 1800));
		int min_interval = int(e.dict_find_int_value("min interval", 60));

		std::string trackerid;
		lazy_entry const* tracker_id = e.dict_find_string("tracker id");
		if (tracker_id)
			trackerid = tracker_id->string_value();
		// parse the response
		lazy_entry const* failure = e.dict_find_string("failure reason");
		if (failure)
		{
			fail(error_code(errors::tracker_failure), status_code
				, failure->string_value().c_str(), interval, min_interval);
			return;
		}

		lazy_entry const* warning = e.dict_find_string("warning message");
		if (warning)
			cb->tracker_warning(tracker_req(), warning->string_value());

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih = tracker_req().info_hash.to_string();

			lazy_entry const* files = e.dict_find_dict("files");
			if (files == 0)
			{
				fail(error_code(errors::invalid_files_entry), -1, ""
					, interval, min_interval);
				return;
			}

			lazy_entry const* scrape_data = files->dict_find_dict(ih.c_str());
			if (scrape_data == 0)
			{
				fail(error_code(errors::invalid_hash_entry), -1, ""
					, interval, min_interval);
				return;
			}
			int complete = int(scrape_data->dict_find_int_value("complete", -1));
			int incomplete = int(scrape_data->dict_find_int_value("incomplete", -1));
			int downloaded = int(scrape_data->dict_find_int_value("downloaded", -1));
			int downloaders = int(scrape_data->dict_find_int_value("downloaders", -1));
			cb->tracker_scrape_response(tracker_req(), complete
				, incomplete, downloaded, downloaders);
			return;
		}

		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();
			for (int i = 0; i < len; i += 6)
			{
				if (len - i < 6) break;

				peer_entry p;
				p.pid.clear();
				error_code ec;
				p.ip = detail::read_v4_address(peers).to_string(ec);
				p.port = detail::read_uint16(peers);
				if (ec) continue;
				peer_list.push_back(p);
			}
		}
		else if (peers_ent && peers_ent->type() == lazy_entry::list_t)
		{
			int len = peers_ent->list_size();
			for (int i = 0; i < len; ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*peers_ent->list_at(i), p)) return;
				peer_list.push_back(p);
			}
		}
		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();
			for (int i = 0; i < len; i += 18)
			{
				if (len - i < 18) break;

				peer_entry p;
				p.pid.clear();
				error_code ec;
				p.ip = detail::read_v6_address(peers).to_string(ec);
				p.port = detail::read_uint16(peers);
				if (ec) continue;
				peer_list.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)
		{
			fail(error_code(errors::invalid_peers_entry), -1, ""
				, interval, min_interval);
			return;
		}


		// look for optional scrape info
		address external_ip;

		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() == address_v4::bytes_type().size())
				external_ip = detail::read_v4_address(p);
#if TORRENT_USE_IPV6
			else if (ip_ent->string_length() == address_v6::bytes_type().size())
				external_ip = detail::read_v6_address(p);
#endif
		}
		
		int complete = int(e.dict_find_int_value("complete", -1));
		int incomplete = int(e.dict_find_int_value("incomplete", -1));

		std::list<address> ip_list;
		if (m_tracker_connection)
		{
			error_code ec;
			ip_list.push_back(m_tracker_connection->socket().remote_endpoint(ec).address());
			std::list<tcp::endpoint> const& epts = m_tracker_connection->endpoints();
			for (std::list<tcp::endpoint>::const_iterator i = epts.begin()
				, end(epts.end()); i != end; ++i)
			{
				ip_list.push_back(i->address());
			}
		}

		cb->tracker_response(tracker_req(), m_tracker_ip, ip_list, peer_list
			, interval, min_interval, complete, incomplete, external_ip, trackerid);
	}
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;
}
	void http_tracker_connection::parse(int status_code, entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		// parse the response
		entry const* failure = e.find_key("failure reason");
		if (failure && failure->type() == entry::string_t)
		{
			fail(status_code, failure->string().c_str());
			return;
		}

		entry const* warning = e.find_key("warning message");
		if (warning && warning->type() == entry::string_t)
		{
			cb->tracker_warning(tracker_req(), warning->string());
		}

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih = tracker_req().info_hash.to_string();

			entry const* files = e.find_key("files");
			if (files == 0 || files->type() != entry::dictionary_t)
			{
				fail(-1, "invalid or missing 'files' entry in scrape response");
				return;
			}

			entry const* scrape_data = files->find_key(ih);
			if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
			{
				fail(-1, "missing or invalid info-hash entry in scrape response");
				return;
			}
			entry const* complete = scrape_data->find_key("complete");
			entry const* incomplete = scrape_data->find_key("incomplete");
			entry const* downloaded = scrape_data->find_key("downloaded");
			if (complete == 0 || incomplete == 0 || downloaded == 0
				|| complete->type() != entry::int_t
				|| incomplete->type() != entry::int_t
				|| downloaded->type() != entry::int_t)
			{
				fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
				return;
			}
			cb->tracker_scrape_response(tracker_req(), int(complete->integer())
				, int(incomplete->integer()), int(downloaded->integer()));
			return;
		}

		entry const* interval = e.find_key("interval");
		if (interval == 0 || interval->type() != entry::int_t)
		{
			fail(-1, "missing or invalid 'interval' entry in tracker response");
			return;
		}

		entry const* peers_ent = e.find_key("peers");
		if (peers_ent && peers_ent->type() == entry::string_t)
		{
			std::string const& peers = peers_ent->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 6) break;

				peer_entry p;
				p.pid.clear();
				error_code ec;
				p.ip = detail::read_v4_address(i).to_string(ec);
				if (ec) continue;
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else if (peers_ent && peers_ent->type() == entry::list_t)
		{
			entry::list_type const& l = peers_ent->list();
			for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*i, p)) return;
				peer_list.push_back(p);
			}
		}
		else
		{
			peers_ent = 0;
		}

		entry const* ipv6_peers = e.find_key("peers6");
		if (ipv6_peers && ipv6_peers->type() == entry::string_t)
		{
			std::string const& peers = ipv6_peers->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 18) break;

				peer_entry p;
				p.pid.clear();
				error_code ec;
				p.ip = detail::read_v6_address(i).to_string(ec);
				if (ec) continue;
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else
		{
			ipv6_peers = 0;
		}

		if (peers_ent == 0 && ipv6_peers == 0)
		{
			fail(-1, "missing 'peers' and 'peers6' entry in tracker response");
			return;
		}


		// look for optional scrape info
		int complete = -1;
		int incomplete = -1;
		address external_ip;

		entry const* ip_ent = e.find_key("external ip");
		if (ip_ent && ip_ent->type() == entry::string_t)
		{
			std::string const& ip = ip_ent->string();
			char const* p = &ip[0];
			if (ip.size() == address_v4::bytes_type::static_size)
				external_ip = detail::read_v4_address(p);
			else if (ip.size() == address_v6::bytes_type::static_size)
				external_ip = detail::read_v6_address(p);
		}
		
		entry const* complete_ent = e.find_key("complete");
		if (complete_ent && complete_ent->type() == entry::int_t)
			complete = int(complete_ent->integer());

		entry const* incomplete_ent = e.find_key("incomplete");
		if (incomplete_ent && incomplete_ent->type() == entry::int_t)
			incomplete = int(incomplete_ent->integer());

		cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
			, incomplete, external_ip);
	}
Beispiel #4
0
	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;
	}