bool udp_tracker_connection::on_announce_response(span<char const> buf)
	{
		if (buf.size() < 20) return false;

		buf = buf.subspan(8);
		restart_read_timeout();

		tracker_response resp;

		resp.interval = aux::read_int32(buf);
		resp.min_interval = 60;
		resp.incomplete = aux::read_int32(buf);
		resp.complete = aux::read_int32(buf);
		int const num_peers = int(buf.size()) / 6;
		if ((buf.size() % 6) != 0)
		{
			fail(error_code(errors::invalid_tracker_response_length));
			return false;
		}

		boost::shared_ptr<request_callback> cb = requester();
#ifndef TORRENT_DISABLE_LOGGING
		if (cb)
		{
			cb->debug_log("<== UDP_TRACKER_RESPONSE [ url: %s ]", tracker_req().url.c_str());
		}
#endif

		if (!cb)
		{
			close();
			return true;
		}

		std::vector<peer_entry> peer_list;
		resp.peers4.reserve(num_peers);
		for (int i = 0; i < num_peers; ++i)
		{
			ipv4_peer_entry e;
			memcpy(&e.ip[0], buf.data(), 4);
			buf = buf.subspan(4);
			e.port = aux::read_uint16(buf);
			resp.peers4.push_back(e);
		}

		std::list<address> ip_list;
		for (std::vector<tcp::endpoint>::const_iterator i = m_endpoints.begin()
			, end(m_endpoints.end()); i != end; ++i)
		{
			ip_list.push_back(i->address());
		}

		cb->tracker_response(tracker_req(), m_target.address(), ip_list
			, resp);

		close();
		return true;
	}
	bool udp_tracker_connection::on_connect_response(span<char const> buf)
	{
		// ignore packets smaller than 16 bytes
		if (buf.size() < 16) return false;

		restart_read_timeout();

		// skip header
		buf = buf.subspan(8);

		// reset transaction
		update_transaction_id();
		std::uint64_t const connection_id = aux::read_int64(buf);

		std::lock_guard<std::mutex> l(m_cache_mutex);
		connection_cache_entry& cce = m_connection_cache[m_target.address()];
		cce.connection_id = connection_id;
		cce.expires = aux::time_now() + seconds(m_man.settings().get_int(settings_pack::udp_tracker_token_expiry));

		if (0 == (tracker_req().kind & tracker_request::scrape_request))
			send_udp_announce();
		else if (0 != (tracker_req().kind & tracker_request::scrape_request))
			send_udp_scrape();
		return true;
	}