# libtorrent todo-list

0 urgent 22 important 63 relevant 7 feasible 177 notes

relevance 3 | ../src/file.cpp:541 | find out what error code is reported when the filesystem does not support hard links.

## find out what error code is reported when the filesystem does not support hard links.

#### ../src/file.cpp:541

    	{
    #ifdef TORRENT_WINDOWS

    #if TORRENT_USE_WSTRING
    #define CreateHardLink_ CreateHardLinkW
    		std::wstring n_exist = convert_to_wstring(file);
    		std::wstring n_link = convert_to_wstring(link);
    #else
    #define CreateHardLink_ CreateHardLinkA
    		std::string n_exist = convert_to_native(file);
    		std::string n_link = convert_to_native(link);
    #endif
    		BOOL ret = CreateHardLink_(n_link.c_str(), n_exist.c_str(), NULL);
    		if (ret)
    		{
    			ec.clear();
    			return;
    		}

    		// something failed. Does the filesystem not support hard links?
    		DWORD const error = GetLastError();
    		if (error != ERROR_NOT_SUPPORTED && error != ERROR_ACCESS_DENIED)
    		{
    			// it's possible CreateHardLink will copy the file internally too,
    			// if the filesystem does not support it.
    			ec.assign(GetLastError(), system_category());
    			return;
    		}

    		// fall back to making a copy

    #else

    		std::string n_exist = convert_to_native(file);
    		std::string n_link = convert_to_native(link);

    		// assume posix's link() function exists
    		int ret = ::link(n_exist.c_str(), n_link.c_str());

    		if (ret == 0)
    		{
    			ec.clear();
    			return;
    		}

    		// most errors are passed through, except for the ones that indicate that
    		// hard links are not supported and require a copy.

relevance 3 | ../src/natpmp.cpp:558 | it would be nice to have a separate NAT-PMP error category

## it would be nice to have a separate NAT-PMP error category

#### ../src/natpmp.cpp:558

    		return;
    	}
    	m->outstanding_request = false;

    	log(msg, l);

    	if (public_port == 0 || lifetime == 0)
    	{
    		// this means the mapping was
    		// successfully closed
    		m->protocol = none;
    	}
    	else
    	{
    		m->expires = aux::time_now() + seconds(int(lifetime * 0.7f));
    		m->external_port = public_port;
    	}

    	if (result != 0)
    	{
    		errors::error_code_enum errors[] =
    		{
    			errors::unsupported_protocol_version,
    			errors::natpmp_not_authorized,
    			errors::network_failure,
    			errors::no_resources,
    			errors::unsupported_opcode,
    		};
    		errors::error_code_enum ev = errors::no_error;
    		if (result >= 1 && result <= 5) ev = errors[result - 1];

    		m->expires = aux::time_now() + hours(2);
    		int const proto = m->protocol;
    		l.unlock();
    		m_callback(index, address(), 0, proto, ev);
    		l.lock();
    	}
    	else if (m->action == mapping_t::action_add)
    	{
    		int const proto = m->protocol;
    		l.unlock();
    		m_callback(index, m_external_ip, m->external_port, proto
    			, errors::no_error);
    		l.lock();
    	}

    	if (m_abort) return;

    	m_currently_mapping = -1;
    	m->action = mapping_t::action_none;
    	m_send_timer.cancel(ec);

relevance 3 | ../src/peer_connection.cpp:2968 | instead of having to ask the torrent whether it's in graceful pause mode or not, the peers should keep that state (and the torrent should update them when it enters graceful pause). When a peer enters graceful pause mode, it should cancel all outstanding requests and clear its request queue.

## instead of having to ask the torrent whether it's in graceful pause mode or not, the peers should keep that state (and the torrent should update them when it enters graceful pause). When a peer enters graceful pause mode, it should cancel all outstanding requests and clear its request queue.

#### ../src/peer_connection.cpp:2968

    		// to disk or are in the disk write cache
    		if (picker.is_piece_finished(p.piece) && !was_finished)
    		{
    #if TORRENT_USE_INVARIANT_CHECKS
    			check_postcondition post_checker2_(t, false);
    #endif
    			t->verify_piece(p.piece);
    		}

    		check_graceful_pause();

    		if (is_disconnecting()) return;

    		if (request_a_block(*t, *this))
    			m_counters.inc_stats_counter(counters::incoming_piece_picks);
    		send_block_requests();
    	}

    	void peer_connection::check_graceful_pause()
    	{
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		if (!t || !t->graceful_pause()) return;

    		if (m_outstanding_bytes > 0) return;

    #ifndef TORRENT_DISABLE_LOGGING
    		peer_log(peer_log_alert::info, "GRACEFUL_PAUSE", "NO MORE DOWNLOAD");
    #endif
    		disconnect(errors::torrent_paused, op_bittorrent);
    	}

    	void peer_connection::on_disk_write_complete(disk_io_job const* j
    		, peer_request p, boost::shared_ptr<torrent> t)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		torrent_ref_holder h(t.get(), "async_write");
    		if (t) t->dec_refcount("async_write");

    #ifndef TORRENT_DISABLE_LOGGING
    		peer_log(peer_log_alert::info, "FILE_ASYNC_WRITE_COMPLETE", "ret: %d piece: %d s: %x l: %x e: %s"
    			, j->ret, p.piece, p.start, p.length, j->error.ec.message().c_str());
    #endif

    		m_counters.inc_stats_counter(counters::queued_write_bytes, -p.length);
    		m_outstanding_writing_bytes -= p.length;

    		TORRENT_ASSERT(m_outstanding_writing_bytes >= 0);

    		// every peer is entitled to allocate a disk buffer if it has no writes outstanding
    		// see the comment in incoming_piece
    		if (m_outstanding_writing_bytes == 0

relevance 3 | ../src/peer_connection.cpp:3850 | once peers are properly put in graceful pause mode, they can cancel all outstanding requests and this test can be removed.

## once peers are properly put in graceful pause mode, they can cancel all outstanding requests and this test can be removed.

#### ../src/peer_connection.cpp:3850

    		}

    		TORRENT_ASSERT(piece >= 0 && piece < m_sent_suggested_pieces.size());

    		if (m_sent_suggested_pieces[piece]) return;
    		m_sent_suggested_pieces.set_bit(piece);

    		write_suggest(piece);
    	}

    	void peer_connection::send_block_requests()
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		TORRENT_ASSERT(t);

    		if (m_disconnecting) return;

    		if (t->graceful_pause()) return;

    		// we can't download pieces in these states
    		if (t->state() == torrent_status::checking_files
    			|| t->state() == torrent_status::checking_resume_data
    			|| t->state() == torrent_status::downloading_metadata
    			|| t->state() == torrent_status::allocating)
    			return;

    		if (int(m_download_queue.size()) >= m_desired_queue_size
    			|| t->upload_mode()) return;

    		bool empty_download_queue = m_download_queue.empty();

    		while (!m_request_queue.empty()
    			&& (int(m_download_queue.size()) < m_desired_queue_size
    				|| m_queued_time_critical > 0))
    		{
    			pending_block block = m_request_queue.front();

    			m_request_queue.erase(m_request_queue.begin());
    			if (m_queued_time_critical) --m_queued_time_critical;

    			// if we're a seed, we don't have a piece picker
    			// so we don't have to worry about invariants getting
    			// out of sync with it
    			if (!t->has_picker()) continue;

    			// this can happen if a block times out, is re-requested and
    			// then arrives "unexpectedly"
    			if (t->picker().is_finished(block.block)

relevance 3 | ../src/peer_list.cpp:1140 | this is not exception safe!

## this is not exception safe!

#### ../src/peer_list.cpp:1140

    				is_v6 ? torrent_peer_allocator_interface::ipv6_peer_type
    				: torrent_peer_allocator_interface::ipv4_peer_type);
    			if (p == NULL) return NULL;

    #if TORRENT_USE_IPV6
    			if (is_v6)
    				new (p) ipv6_peer(remote, true, src);
    			else
    #endif
    				new (p) ipv4_peer(remote, true, src);

    #if TORRENT_USE_ASSERTS
    			p->in_use = true;
    #endif

    			if (!insert_peer(p, iter, flags, state))
    			{
    #if TORRENT_USE_ASSERTS
    				p->in_use = false;
    #endif
    				m_peer_allocator.free_peer_entry(p);
    				return 0;
    			}
    			state->first_time_seen = true;
    		}
    		else
    		{
    			p = *iter;
    			TORRENT_ASSERT(p->in_use);
    			update_peer(p, src, flags, remote, 0);
    			state->first_time_seen = false;
    		}

    		return p;
    	}

    	torrent_peer* peer_list::connect_one_peer(int session_time, torrent_state* state)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    		if (m_finished != state->is_finished)
    			recalculate_connect_candidates(state);

    		// clear out any peers from the cache that no longer
    		// are connection candidates
    		for (std::vector<torrent_peer*>::iterator i = m_candidate_cache.begin();
    			i != m_candidate_cache.end();)
    		{
    			if (!is_connect_candidate(**i))
    				i = m_candidate_cache.erase(i);

relevance 3

../src/session_impl.cpp:3874

it would probably make sense to have a separate list of peers that are eligible for optimistic unchoke, similar to the torrents perhaps this could even iterate over the pool allocators of torrent_peer objects. It could probably be done in a single pass and collect the n best candidates. maybe just a queue of peers would make even more sense, just pick the next peer in the queue for unchoking. It would be O(1).

## it would probably make sense to have a separate list of peers that are eligible for optimistic unchoke, similar to the torrents perhaps this could even iterate over the pool allocators of torrent_peer objects. It could probably be done in a single pass and collect the n best candidates. maybe just a queue of peers would make even more sense, just pick the next peer in the queue for unchoking. It would be O(1).

#### ../src/session_impl.cpp:3874

    			, torrent_peer const* const r)
    		{
    			return l->last_optimistically_unchoked
    				< r->last_optimistically_unchoked;
    		}
    	}

    	void session_impl::recalculate_optimistic_unchoke_slots()
    	{
    		INVARIANT_CHECK;

    		TORRENT_ASSERT(is_single_thread());
    		if (m_stats_counters[counters::num_unchoke_slots] == 0) return;

    		std::vector<torrent_peer*> opt_unchoke;

    		// collect the currently optimistically unchoked peers here, so we can
    		// choke them when we've found new optimistic unchoke candidates.
    		std::vector<torrent_peer*> prev_opt_unchoke;

    		for (connection_map::iterator i = m_connections.begin()
    			, end(m_connections.end()); i != end; ++i)
    		{
    			peer_connection* p = i->get();
    			TORRENT_ASSERT(p);
    			torrent_peer* pi = p->peer_info_struct();
    			if (!pi) continue;
    			if (pi->web_seed) continue;

    			if (pi->optimistically_unchoked)
    			{
    				prev_opt_unchoke.push_back(pi);
    			}

    			torrent* t = p->associated_torrent().lock().get();
    			if (!t) continue;

relevance 3 | ../src/session_impl.cpp:3898 | peers should know whether their torrent is paused or not, instead of having to ask it over and over again

## peers should know whether their torrent is paused or not, instead of having to ask it over and over again

#### ../src/session_impl.cpp:3898

    		// choke them when we've found new optimistic unchoke candidates.
    		std::vector<torrent_peer*> prev_opt_unchoke;

    		for (connection_map::iterator i = m_connections.begin()
    			, end(m_connections.end()); i != end; ++i)
    		{
    			peer_connection* p = i->get();
    			TORRENT_ASSERT(p);
    			torrent_peer* pi = p->peer_info_struct();
    			if (!pi) continue;
    			if (pi->web_seed) continue;

    			if (pi->optimistically_unchoked)
    			{
    				prev_opt_unchoke.push_back(pi);
    			}

    			torrent* t = p->associated_torrent().lock().get();
    			if (!t) continue;

    			if (t->is_paused()) continue;

    			if (!p->is_connecting()
    				&& !p->is_disconnecting()
    				&& p->is_peer_interested()
    				&& t->free_upload_slots()
    				&& (p->is_choked() || pi->optimistically_unchoked)
    				&& !p->ignore_unchoke_slots()
    				&& t->valid_metadata())
    			{
    				opt_unchoke.push_back(pi);
    			}
    		}

    		// find the peers that has been waiting the longest to be optimistically
    		// unchoked

    		int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
    		int const allowed_unchoke_slots = m_stats_counters[counters::num_unchoke_slots];
    		if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, allowed_unchoke_slots / 5);
    		if (num_opt_unchoke > int(opt_unchoke.size())) num_opt_unchoke =
    			int(opt_unchoke.size());

    		// find the n best optimistic unchoke candidates
    		std::partial_sort(opt_unchoke.begin()
    			, opt_unchoke.begin() + num_opt_unchoke
    			, opt_unchoke.end(), &last_optimistic_unchoke_cmp);

    #ifndef TORRENT_DISABLE_EXTENSIONS
    		if (m_session_extension_features & plugin::optimistic_unchoke_feature)
    		{

relevance 3 | ../src/session_impl.cpp:4175 | there should be a pre-calculated list of all peers eligible for unchoking

## there should be a pre-calculated list of all peers eligible for unchoking

#### ../src/session_impl.cpp:4175

    			if (want_peers_download.empty() && want_peers_finished.empty()) break;
    			// if we have gone a whole loop without
    			// handing out a single connection, break
    			if (steps_since_last_connect > num_torrents + 1) break;
    			// maintain the global limit on number of connections
    			if (num_connections() >= m_settings.get_int(settings_pack::connections_limit)) break;
    		}
    	}

    	void session_impl::recalculate_unchoke_slots()
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    		time_point const now = aux::time_now();
    		time_duration const unchoke_interval = now - m_last_choke;
    		m_last_choke = now;

    		// build list of all peers that are
    		// unchokable.
    		std::vector<peer_connection*> peers;
    		for (connection_map::iterator i = m_connections.begin();
    			i != m_connections.end();)
    		{
    			boost::shared_ptr<peer_connection> p = *i;
    			TORRENT_ASSERT(p);
    			++i;
    			torrent* const t = p->associated_torrent().lock().get();
    			torrent_peer* const pi = p->peer_info_struct();

    			if (p->ignore_unchoke_slots() || t == 0 || pi == 0
    				|| pi->web_seed || t->is_paused())
    			{
    				p->reset_choke_counters();
    				continue;
    			}

    			if (!p->is_peer_interested()
    				|| p->is_disconnecting()
    				|| p->is_connecting())
    			{
    				// this peer is not unchokable. So, if it's unchoked
    				// already, make sure to choke it.
    				if (p->is_choked())
    				{
    					p->reset_choke_counters();
    					continue;
    				}
    				if (pi && pi->optimistically_unchoked)
    				{
    					m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);

relevance 3 | ../src/torrent.cpp:9779 | this really needs to be moved to do_async_save_resume_data. flags need to be passed on

## this really needs to be moved to do_async_save_resume_data. flags need to be passed on

#### ../src/torrent.cpp:9779

    				alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    					, m_error);
    				return;
    			}

    			// storage may be NULL during shutdown
    			if (!m_storage)
    			{
    				TORRENT_ASSERT(m_abort);
    				alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    					, boost::asio::error::operation_aborted);
    				return;
    			}

    			boost::shared_ptr<entry> rd(new entry);
    			write_resume_data(*rd);
    			alerts().emplace_alert<save_resume_data_alert>(rd, get_handle());
    			return;
    		}

    		if ((flags & torrent_handle::flush_disk_cache) && m_storage.get())
    			m_ses.disk_thread().async_release_files(m_storage.get());

    		m_ses.queue_async_resume_data(shared_from_this());
    	}

    	bool torrent::do_async_save_resume_data()
    	{
    		if (!need_loaded())
    		{
    			alerts().emplace_alert<save_resume_data_failed_alert>(get_handle(), m_error);
    			return false;
    		}
    		// storage may be NULL during shutdown
    		if (!m_storage)
    		{
    			TORRENT_ASSERT(m_abort);
    			alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    				, boost::asio::error::operation_aborted);
    			return false;
    		}
    		inc_refcount("save_resume");
    		m_ses.disk_thread().async_save_resume_data(m_storage.get()
    			, boost::bind(&torrent::on_save_resume_data, shared_from_this(), _1));
    		return true;
    	}

    	bool torrent::should_check_files() const
    	{
    		TORRENT_ASSERT(is_single_thread());
    		// #error should m_allow_peers really affect checking?

relevance 3 | ../src/upnp.cpp:127 | listen_interface is not used. It's meant to bind the broadcast socket. it would probably have to be changed to a vector of interfaces to bind to though, since the broadcast socket opens one socket per local interface by default

## listen_interface is not used. It's meant to bind the broadcast socket. it would probably have to be changed to a vector of interfaces to bind to though, since the broadcast socket opens one socket per local interface by default

#### ../src/upnp.cpp:127

    	, portmap_callback_t const& cb, log_callback_t const& lcb
    	, bool ignore_nonrouters)
    	: m_user_agent(user_agent)
    	, m_callback(cb)
    	, m_log_callback(lcb)
    	, m_retry_count(0)
    	, m_io_service(ios)
    	, m_resolver(ios)
    	, m_socket(udp::endpoint(address_v4::from_string("239.255.255.250"
    		, ignore_error), 1900))
    	, m_broadcast_timer(ios)
    	, m_refresh_timer(ios)
    	, m_map_timer(ios)
    	, m_disabled(false)
    	, m_closing(false)
    	, m_ignore_non_routers(ignore_nonrouters)
    	, m_last_if_update(min_time())
    {
    	TORRENT_ASSERT(cb);

    	TORRENT_UNUSED(listen_interface);
    }

    void upnp::start()
    {
    	error_code ec;
    	m_socket.open(boost::bind(&upnp::on_reply, self(), _1, _2, _3)
    		, m_refresh_timer.get_io_service(), ec);

    	m_mappings.reserve(10);
    }

    upnp::~upnp()
    {
    }

    void upnp::discover_device()
    {
    	mutex::scoped_lock l(m_mutex);
    	if (m_socket.num_send_sockets() == 0)
    		log("No network interfaces to broadcast to", l);

    	discover_device_impl(l);
    }

    void upnp::log(char const* msg, mutex::scoped_lock& l)
    {
    	l.unlock();
    	m_log_callback(msg);
    	l.lock();
    }

relevance 3 | ../src/kademlia/node_id.cpp:54 | the XORing should be done at full words instead of bytes

## the XORing should be done at full words instead of bytes

#### ../src/kademlia/node_id.cpp:54

    #include "libtorrent/kademlia/node_id.hpp"
    #include "libtorrent/kademlia/node_entry.hpp"
    #include "libtorrent/hasher.hpp"
    #include "libtorrent/assert.hpp"
    #include "libtorrent/broadcast_socket.hpp" // for is_local et.al
    #include "libtorrent/socket_io.hpp" // for hash_address
    #include "libtorrent/random.hpp" // for random
    #include "libtorrent/hasher.hpp" // for hasher
    #include "libtorrent/crc32c.hpp" // for crc32c

    namespace libtorrent { namespace dht
    {

    // returns the distance between the two nodes
    // using the kademlia XOR-metric
    node_id distance(node_id const& n1, node_id const& n2)
    {
    	node_id ret;
    	node_id::iterator k = ret.begin();
    	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
    		, end(n1.end()); i != end; ++i, ++j, ++k)
    	{
    		*k = *i ^ *j;
    	}
    	return ret;
    }

    // returns true if: distance(n1, ref) < distance(n2, ref)
    bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
    {

relevance 3 | ../src/kademlia/node_id.cpp:66 | the XORing should be done at full words instead of bytes

## the XORing should be done at full words instead of bytes

#### ../src/kademlia/node_id.cpp:66

    namespace libtorrent { namespace dht
    {

    // returns the distance between the two nodes
    // using the kademlia XOR-metric
    node_id distance(node_id const& n1, node_id const& n2)
    {
    	node_id ret;
    	node_id::iterator k = ret.begin();
    	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
    		, end(n1.end()); i != end; ++i, ++j, ++k)
    	{
    		*k = *i ^ *j;
    	}
    	return ret;
    }

    // returns true if: distance(n1, ref) < distance(n2, ref)
    bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
    {
    	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
    		, k = ref.begin(), end(n1.end()); i != end; ++i, ++j, ++k)
    	{
    		boost::uint8_t lhs = (*i ^ *k);
    		boost::uint8_t rhs = (*j ^ *k);
    		if (lhs < rhs) return true;
    		if (lhs > rhs) return false;
    	}
    	return false;
    }

    // returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
    // useful for finding out which bucket a node belongs to
    int distance_exp(node_id const& n1, node_id const& n2)
    {

relevance 3 | ../src/kademlia/node_id.cpp:82 | the xoring should be done at full words and _builtin_clz() could be used as the last step

## the xoring should be done at full words and _builtin_clz() could be used as the last step

#### ../src/kademlia/node_id.cpp:82

    }

    // returns true if: distance(n1, ref) < distance(n2, ref)
    bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
    {
    	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
    		, k = ref.begin(), end(n1.end()); i != end; ++i, ++j, ++k)
    	{
    		boost::uint8_t lhs = (*i ^ *k);
    		boost::uint8_t rhs = (*j ^ *k);
    		if (lhs < rhs) return true;
    		if (lhs > rhs) return false;
    	}
    	return false;
    }

    // returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
    // useful for finding out which bucket a node belongs to
    int distance_exp(node_id const& n1, node_id const& n2)
    {
    	int byte = node_id::size - 1;
    	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
    		, end(n1.end()); i != end; ++i, ++j, --byte)
    	{
    		TORRENT_ASSERT(byte >= 0);
    		boost::uint8_t t = *i ^ *j;
    		if (t == 0) continue;
    		// we have found the first non-zero byte
    		// return the bit-number of the first bit
    		// that differs
    		int const bit = byte * 8;
    		for (int b = 7; b >= 0; --b)
    			if (t >= (1 << b)) return bit + b;
    		return bit;
    	}

    	return 0;
    }

    node_id generate_id_impl(address const& ip_, boost::uint32_t r)
    {
    	boost::uint8_t* ip = 0;

    	static const boost::uint8_t v4mask[] = { 0x03, 0x0f, 0x3f, 0xff };
    #if TORRENT_USE_IPV6
    	static const boost::uint8_t v6mask[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
    #endif
    	boost::uint8_t const* mask = 0;
    	int num_octets = 0;

    	address_v4::bytes_type b4;

relevance 3 | ../src/kademlia/routing_table.cpp:688 | the call to compare_ip_cidr here is expensive. peel off some layers of abstraction here to make it quicker. Look at xoring and using _builtin_ctz()

## the call to compare_ip_cidr here is expensive. peel off some layers of abstraction here to make it quicker. Look at xoring and using _builtin_ctz()

#### ../src/kademlia/routing_table.cpp:688

    	// that we have an updated RTT
    	j = std::find_if(rb.begin(), rb.end(), boost::bind(&node_entry::id, _1) == e.id);
    	if (j != rb.end())
    	{
    		// a new IP address just claimed this node-ID
    		// ignore it
    		if (j->addr() != e.addr() || j->port() != e.port())
    			return failed_to_add;

    		TORRENT_ASSERT(j->id == e.id && j->ep() == e.ep());
    		j->timeout_count = 0;
    		j->update_rtt(e.rtt);
    		e = *j;
    		erase_one(m_ips, j->addr().to_v4().to_bytes());
    		rb.erase(j);
    	}

    	if (m_settings.restrict_routing_ips)
    	{
    		// don't allow multiple entries from IPs very close to each other
    		j = std::find_if(b.begin(), b.end(), boost::bind(&compare_ip_cidr, _1, e));
    		if (j == b.end())
    		{
    			j = std::find_if(rb.begin(), rb.end(), boost::bind(&compare_ip_cidr, _1, e));
    			if (j == rb.end()) goto ip_ok;
    		}

    		// we already have a node in this bucket with an IP very
    		// close to this one. We know that it's not the same, because
    		// it claims a different node-ID. Ignore this to avoid attacks
    #ifndef TORRENT_DISABLE_LOGGING
    		char hex_id1[41];
    		to_hex(e.id.data(), 20, hex_id1);
    		char hex_id2[41];
    		to_hex(j->id.data(), 20, hex_id2);
    		m_log->log(dht_logger::routing_table, "ignoring node: %s %s existing node: %s %s"
    			, hex_id1, print_address(e.addr()).c_str()
    			, hex_id2, print_address(j->addr()).c_str());
    #endif
    		return failed_to_add;
    	}
    ip_ok:

    	// can we split the bucket?
    	// only nodes that haven't failed can split the bucket, and we can only
    	// split the last bucket
    	bool const can_split = (boost::next(i) == m_buckets.end()
    		&& m_buckets.size() < 159)
    		&& e.fail_count() == 0
    		&& (i == m_buckets.begin() || boost::prior(i)->live_nodes.size() > 1);

relevance 3 | ../src/kademlia/rpc_manager.cpp:87 | move this into it's own .cpp file

## move this into it's own .cpp file

#### ../src/kademlia/rpc_manager.cpp:87

    void intrusive_ptr_add_ref(observer const* o)
    {
    	TORRENT_ASSERT(o != 0);
    	TORRENT_ASSERT(o->m_refs < 0xffff);
    	++o->m_refs;
    }

    void intrusive_ptr_release(observer const* o)
    {
    	TORRENT_ASSERT(o != 0);
    	TORRENT_ASSERT(o->m_refs > 0);
    	if (--o->m_refs == 0)
    	{
    		boost::intrusive_ptr<traversal_algorithm> ta = o->algorithm();
    		(const_cast<observer*>(o))->~observer();
    		ta->free_observer(const_cast<observer*>(o));
    	}
    }

    dht_observer* observer::get_observer() const
    {
    	return m_algorithm->get_node().observer();
    }

    void observer::set_target(udp::endpoint const& ep)
    {
    	m_sent = clock_type::now();

    	m_port = ep.port();
    #if TORRENT_USE_IPV6
    	if (ep.address().is_v6())
    	{
    		flags |= flag_ipv6_address;
    		m_addr.v6 = ep.address().to_v6().to_bytes();
    	}
    	else
    #endif
    	{
    		flags &= ~flag_ipv6_address;
    		m_addr.v4 = ep.address().to_v4().to_bytes();
    	}
    }

    address observer::target_addr() const
    {
    #if TORRENT_USE_IPV6
    	if (flags & flag_ipv6_address)
    		return address_v6(m_addr.v6);
    	else
    #endif

relevance 3 | ../include/libtorrent/stat.hpp:263 | everything but payload counters and rates could probably be removed from here

## everything but payload counters and rates could probably be removed from here

#### ../include/libtorrent/stat.hpp:263

    		// peer_connection is opened and have some previous
    		// transfers from earlier connections.
    		void add_stat(boost::int64_t downloaded, boost::int64_t uploaded)
    		{
    			m_stat[download_payload].offset(downloaded);
    			m_stat[upload_payload].offset(uploaded);
    		}

    		int last_payload_downloaded() const
    		{ return m_stat[download_payload].counter(); }
    		int last_payload_uploaded() const
    		{ return m_stat[upload_payload].counter(); }
    		int last_protocol_downloaded() const
    		{ return m_stat[download_protocol].counter(); }
    		int last_protocol_uploaded() const
    		{ return m_stat[upload_protocol].counter(); }

    		// these are the channels we keep stats for
    		enum
    		{
    			upload_payload,
    			upload_protocol,
    			download_payload,
    			download_protocol,
    			upload_ip_protocol,
    			download_ip_protocol,
    			num_channels
    		};

    		void clear()
    		{
    			for (int i = 0; i < num_channels; ++i)
    				m_stat[i].clear();
    		}

    		stat_channel const& operator[](int i) const
    		{
    			TORRENT_ASSERT(i >= 0 && i < num_channels);
    			return m_stat[i];
    		}

    	private:

    		stat_channel m_stat[num_channels];
    	};

    }

    #endif // TORRENT_STAT_HPP_INCLUDED

relevance 3 | ../include/libtorrent/torrent.hpp:1389 | factor out the links (as well as update_list() to a separate class that torrent can inherit)

## factor out the links (as well as update_list() to a separate class that torrent can inherit)

#### ../include/libtorrent/torrent.hpp:1389

    		// this was the last time _we_ saw a seed in this swarm
    		time_t m_last_seen_complete;

    		// this is the time last any of our peers saw a seed
    		// in this swarm
    		time_t m_swarm_last_seen_complete;

    		// keep a copy if the info-hash here, so it can be accessed from multiple
    		// threads, and be cheap to access from the client
    		sha1_hash m_info_hash;

    	public:
    		// these are the lists this torrent belongs to. For more
    		// details about each list, see session_impl.hpp. Each list
    		// represents a group this torrent belongs to and makes it
    		// efficient to enumerate only torrents belonging to a specific
    		// group. Such as torrents that want peer connections or want
    		// to be ticked etc.

    		link m_links[aux::session_interface::num_torrent_lists];

    	private:

    		// m_num_verified = m_verified.count()
    		boost::uint32_t m_num_verified;

    		// this timestamp is kept in session-time, to
    		// make it fit in 16 bits
    		boost::uint16_t m_last_saved_resume;

    		// if this torrent is running, this was the time
    		// when it was started. This is used to have a
    		// bias towards keeping seeding torrents that
    		// recently was started, to avoid oscillation
    		// this is specified at a second granularity
    		// in session-time. see session_impl for details.
    		// the reference point is stepped forward every 4
    		// hours to keep the timestamps fit in 16 bits
    		boost::uint16_t m_started;

    		// if we're a seed, this is the session time
    		// timestamp of when we became one
    		boost::uint16_t m_became_seed;

    		// if we're finished, this is the session time
    		// timestamp of when we finished
    		boost::uint16_t m_became_finished;

    		// when checking, this is the first piece we have not
    		// issued a hash job for

relevance 3 | ../include/libtorrent/torrent_handle.hpp:247 | consider replacing all the setters and getters for pause, resume, stop-when-ready, share-mode, upload-mode, super-seeding, apply-ip-filter, resolve-countries, pinned, sequential-download, seed-mode with just set_flags() and clear_flags() using the flags from add_torrent_params. Perhaps those flags should have a more generic name.

## consider replacing all the setters and getters for pause, resume, stop-when-ready, share-mode, upload-mode, super-seeding, apply-ip-filter, resolve-countries, pinned, sequential-download, seed-mode with just set_flags() and clear_flags() using the flags from add_torrent_params. Perhaps those flags should have a more generic name.

#### ../include/libtorrent/torrent_handle.hpp:247

    	// 	expensive if done from within a GUI thread that needs to stay
    	// 	responsive. Try to avoid querying for information you don't need, and
    	// 	try to do it in as few calls as possible. You can get most of the
    	// 	interesting information about a torrent from the
    	// 	torrent_handle::status() call.
    	//
    	// The default constructor will initialize the handle to an invalid state.
    	// Which means you cannot perform any operation on it, unless you first
    	// assign it a valid handle. If you try to perform any operation on an
    	// uninitialized handle, it will throw ``invalid_handle``.
    	//
    	// .. warning::
    	// 	All operations on a torrent_handle may throw libtorrent_exception
    	// 	exception, in case the handle is no longer referring to a torrent.
    	// 	There is one exception is_valid() will never throw. Since the torrents
    	// 	are processed by a background thread, there is no guarantee that a
    	// 	handle will remain valid between two calls.
    	//
    	struct TORRENT_EXPORT torrent_handle
    	{
    		friend class invariant_access;
    		friend struct aux::session_impl;
    		friend class session;
    		friend struct session_handle;
    		friend struct feed;
    		friend class torrent;
    		friend std::size_t hash_value(torrent_handle const& th);

    		// constructs a torrent handle that does not refer to a torrent.
    		// i.e. is_valid() will return false.
    		torrent_handle() {}

    		torrent_handle(torrent_handle const& t)
    		{ if (!t.m_torrent.expired()) m_torrent = t.m_torrent; }

    #if __cplusplus >= 201103L
    		torrent_handle& operator=(torrent_handle const&) = default;
    #endif

    		// flags for add_piece().
    		enum flags_t { overwrite_existing = 1 };

    		// This function will write ``data`` to the storage as piece ``piece``,
    		// as if it had been downloaded from a peer. ``data`` is expected to
    		// point to a buffer of as many bytes as the size of the specified piece.
    		// The data in the buffer is copied and passed on to the disk IO thread
    		// to be written at a later point.
    		//
    		// By default, data that's already been downloaded is not overwritten by
    		// this buffer. If you trust this data to be correct (and pass the piece
    		// hash check) you may pass the overwrite_existing flag. This will

relevance 3 | ../include/libtorrent/torrent_handle.hpp:494 | unify url_seed and http_seed with just web_seed, using the web_seed_entry.

## unify url_seed and http_seed with just web_seed, using the web_seed_entry.

#### ../include/libtorrent/torrent_handle.hpp:494

    		// announce url for the tracker as well as an int ``tier``, which is
    		// specifies the order in which this tracker is tried. If you want
    		// libtorrent to use another list of trackers for this torrent, you can
    		// use ``replace_trackers()`` which takes a list of the same form as the
    		// one returned from ``trackers()`` and will replace it. If you want an
    		// immediate effect, you have to call force_reannounce(). See
    		// announce_entry.
    		//
    		// ``add_tracker()`` will look if the specified tracker is already in the
    		// set. If it is, it doesn't do anything. If it's not in the current set
    		// of trackers, it will insert it in the tier specified in the
    		// announce_entry.
    		//
    		// The updated set of trackers will be saved in the resume data, and when
    		// a torrent is started with resume data, the trackers from the resume
    		// data will replace the original ones.
    		std::vector<announce_entry> trackers() const;
    		void replace_trackers(std::vector<announce_entry> const&) const;
    		void add_tracker(announce_entry const&) const;

    		// ``add_url_seed()`` adds another url to the torrent's list of url
    		// seeds. If the given url already exists in that list, the call has no
    		// effect. The torrent will connect to the server and try to download
    		// pieces from it, unless it's paused, queued, checking or seeding.
    		// ``remove_url_seed()`` removes the given url if it exists already.
    		// ``url_seeds()`` return a set of the url seeds currently in this
    		// torrent. Note that URLs that fails may be removed automatically from
    		// the list.
    		//
    		// See http-seeding_ for more information.
    		void add_url_seed(std::string const& url) const;
    		void remove_url_seed(std::string const& url) const;
    		std::set<std::string> url_seeds() const;

    		// These functions are identical as the ``*_url_seed()`` variants, but
    		// they operate on `BEP 17`_ web seeds instead of `BEP 19`_.
    		//
    		// See http-seeding_ for more information.
    		void add_http_seed(std::string const& url) const;
    		void remove_http_seed(std::string const& url) const;
    		std::set<std::string> http_seeds() const;

    		// add the specified extension to this torrent. The ``ext`` argument is
    		// a function that will be called from within libtorrent's context
    		// passing in the internal torrent object and the specified userdata
    		// pointer. The function is expected to return a shared pointer to
    		// a torrent_plugin instance.
    		void add_extension(
    			boost::function<boost::shared_ptr<torrent_plugin>(torrent_handle const&, void*)> const& ext
    			, void* userdata = 0);

relevance 3 | ../include/libtorrent/web_peer_connection.hpp:131 | if we make this be a disk_buffer_holder instead we would save a copy use allocate_disk_receive_buffer and release_disk_receive_buffer

## if we make this be a disk_buffer_holder instead we would save a copy use allocate_disk_receive_buffer and release_disk_receive_buffer

#### ../include/libtorrent/web_peer_connection.hpp:131

    		boost::optional<piece_block_progress> downloading_piece_progress() const TORRENT_OVERRIDE;

    		void handle_padfile();

    		// this has one entry per http-request
    		// (might be more than the bt requests)
    		struct file_request_t
    		{
    			int file_index;
    			int length;
    			boost::int64_t start;
    		};
    		std::deque<file_request_t> m_file_requests;

    		std::string m_url;

    		web_seed_t* m_web;

    		// this is used for intermediate storage of pieces to be delivered to the
    		// bittorrent engine
    		std::vector<char> m_piece;

    		// the number of bytes we've forwarded to the incoming_payload() function
    		// in the current HTTP response. used to know where in the buffer the
    		// next response starts
    		int m_received_body;

    		// this is the offset inside the current receive
    		// buffer where the next chunk header will be.
    		// this is updated for each chunk header that's
    		// parsed. It does not necessarily point to a valid
    		// offset in the receive buffer, if we haven't received
    		// it yet. This offset never includes the HTTP header
    		int m_chunk_pos;

    		// this is the number of bytes we've already received
    		// from the next chunk header we're waiting for
    		int m_partial_chunk_header;

    		// the number of responses we've received so far on
    		// this connection
    		int m_num_responses;
    	};
    }

    #endif // TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED

relevance 3 | ../include/libtorrent/kademlia/routing_table.hpp:99 | to improve memory locality and scanning performance, turn the routing table into a single vector with boundaries for the nodes instead. Perhaps replacement nodes should be in a separate vector.

## to improve memory locality and scanning performance, turn the routing table into a single vector with boundaries for the nodes instead. Perhaps replacement nodes should be in a separate vector.

#### ../include/libtorrent/kademlia/routing_table.hpp:99

    // * Nodes are not marked as being stale, they keep a counter
    // 	that tells how many times in a row they have failed. When
    // 	a new node is to be inserted, the node that has failed
    // 	the most times is replaced. If none of the nodes in the
    // 	bucket has failed, then it is put in the replacement
    // 	cache (just like in the paper).

    namespace impl
    {
    	template <typename F>
    	inline void forwarder(void* userdata, node_entry const& node)
    	{
    		F* f = reinterpret_cast<F*>(userdata);
    		(*f)(node);
    	}
    }

    class TORRENT_EXTRA_EXPORT routing_table : boost::noncopyable
    {
    public:
    	typedef std::vector<routing_table_node> table_t;

    	routing_table(node_id const& id, int bucket_size
    		, dht_settings const& settings
    		, dht_logger* log);

    #ifndef TORRENT_NO_DEPRECATE
    	void status(session_status& s) const;
    #endif

    	void status(std::vector<dht_routing_bucket>& s) const;

    	void node_failed(node_id const& id, udp::endpoint const& ep);

    	// adds an endpoint that will never be added to
    	// the routing table
    	void add_router_node(udp::endpoint router);

    	// iterates over the router nodes added
    	typedef std::set<udp::endpoint>::const_iterator router_iterator;
    	router_iterator router_begin() const { return m_router_nodes.begin(); }
    	router_iterator router_end() const { return m_router_nodes.end(); }

    	enum add_node_status_t {
    		failed_to_add = 0,
    		node_added,
    		need_bucket_split
    	};
    	add_node_status_t add_node_impl(node_entry e);

    	bool add_node(node_entry e);

relevance 3 | ../include/libtorrent/aux_/allocating_handler.hpp:77 | make sure the handlers we pass in are potentially movable!

## make sure the handlers we pass in are potentially movable!

#### ../include/libtorrent/aux_/allocating_handler.hpp:77

    			: used(false)
    		{}

    		bool used;
    #else
    		handler_storage() {}
    #endif
    		boost::aligned_storage<Size> bytes;
    	private:
    		handler_storage(handler_storage const&);
    	};

    	// this class is a wrapper for an asio handler object. Its main purpose
    	// is to pass along additional parameters to the asio handler allocator
    	// function, as well as providing a distinct type for the handler
    	// allocator function to overload on
    	template <class Handler, std::size_t Size>
    	struct allocating_handler
    	{

    #if !defined BOOST_NO_CXX11_RVALUE_REFERENCES
    		allocating_handler(
    			Handler&& h, handler_storage<Size>& s)
    			: handler(std::move(h))
    			, storage(s)
    		{}
    #endif

    		allocating_handler(
    			Handler const& h, handler_storage<Size>& s)
    			: handler(h)
    			, storage(s)
    		{}

    #if !defined BOOST_NO_CXX11_VARIADIC_TEMPLATES \
    		&& !defined BOOST_NO_CXX11_RVALUE_REFERENCES
    		template <class... A>
    		void operator()(A&&... a) const
    		{
    			handler(std::forward<A>(a)...);
    		}
    #else
    		template <class A0>
    		void operator()(A0 const& a0) const
    		{
    			handler(a0);
    		}

    		template <class A0, class A1>
    		void operator()(A0 const& a0, A1 const& a1) const
    		{

relevance 2 | ../test/test_dht.cpp:514 | split this test up into smaller test cases

## split this test up into smaller test cases

#### ../test/test_dht.cpp:514

    		va_end(v);
    		m_log.push_back(buf);
    	}
    	virtual void log_packet(message_direction_t dir, char const* pkt, int len
    		, udp::endpoint node) TORRENT_OVERRIDE {}
    	virtual bool on_dht_request(char const* query, int query_len
    		, dht::msg const& request, entry& response) TORRENT_OVERRIDE { return false; }

    	std::vector<std::string> m_log;
    };

    dht_settings test_settings()
    {
    	dht_settings sett;
    	sett.max_torrents = 4;
    	sett.max_dht_items = 4;
    	sett.enforce_node_id = false;
    	return sett;
    }

    TORRENT_TEST(dht)
    {
    	dht_settings sett = test_settings();
    	mock_socket s;
    	obs observer;
    	counters cnt;
    	dht::node node(&s, sett, node_id(0), &observer, cnt);

    	// DHT should be running on port 48199 now
    	bdecode_node response;
    	char error_string[200];
    	bool ret;

    	// ====== ping ======
    	udp::endpoint source(address::from_string("10.0.0.1"), 20);
    	send_dht_request(node, "ping", source, &response);

    	dht::key_desc_t pong_desc[] = {
    		{"y", bdecode_node::string_t, 1, 0},
    		{"t", bdecode_node::string_t, 2, 0},
    		{"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
    			{"id", bdecode_node::string_t, 20, key_desc_t::last_child},
    	};

    	bdecode_node pong_keys[4];

    	fprintf(stdout, "msg: %s\n", print_entry(response).c_str());
    	ret = dht::verify_message(response, pong_desc, pong_keys, error_string
    		, sizeof(error_string));
    	TEST_CHECK(ret);
    	if (ret)

relevance 2 | ../test/test_dht.cpp:2141 | split this up into smaller test cases

## split this up into smaller test cases

#### ../test/test_dht.cpp:2141

    	TEST_EQUAL(to_hex(std::string(signature, 64))
    		, "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d"
    		"df9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08");

    	sha1_hash target_id = item_target_id(test_salt, public_key);
    	TEST_EQUAL(to_hex(target_id.to_string()), "411eba73b6f087ca51a3795d9c8c938d365e32c1");
    }

    TORRENT_TEST(signing_test3)
    {
    	// test vector 3

    	// test content
    	std::pair<char const*, int> test_content("12:Hello World!", 15);

    	sha1_hash target_id = item_target_id(test_content);
    	TEST_EQUAL(to_hex(target_id.to_string()), "e5f96f6f38320f0f33959cb4d3d656452117aadb");
    }

    TORRENT_TEST(verify_message)
    {
    	char error_string[200];

    	// test verify_message
    	static const key_desc_t msg_desc[] = {
    		{"A", bdecode_node::string_t, 4, 0},
    		{"B", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
    			{"B1", bdecode_node::string_t, 0, 0},
    			{"B2", bdecode_node::string_t, 0, key_desc_t::last_child},
    		{"C", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
    			{"C1", bdecode_node::string_t, 0, 0},
    			{"C2", bdecode_node::string_t, 0, key_desc_t::last_child},
    	};

    	bdecode_node msg_keys[7];

    	bdecode_node ent;

    	error_code ec;
    	char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee";
    	bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec);
    	fprintf(stdout, "%s\n", print_entry(ent).c_str());

    	bool ret = verify_message(ent, msg_desc, msg_keys, error_string
    		, sizeof(error_string));
    	TEST_CHECK(ret);
    	TEST_CHECK(msg_keys[0]);
    	if (msg_keys[0]) TEST_EQUAL(msg_keys[0].string_value(), "test");
    	TEST_CHECK(msg_keys[1]);
    	TEST_CHECK(msg_keys[2]);

relevance 2 | ../test/test_piece_picker.cpp:281 | split this up into smaller tests (where we print_title)

## split this up into smaller tests (where we print_title)

#### ../test/test_piece_picker.cpp:281

    	std::vector<piece_block> picked;
    	counters pc;
    	p->pick_pieces(string2vec(availability), picked
    		, num_blocks, prefer_contiguous_blocks, peer_struct
    		, options, suggested_pieces, 20, pc);
    	print_pick(picked);
    	TEST_CHECK(verify_pick(p, picked));
    	return picked;
    }

    int test_pick(boost::shared_ptr<piece_picker> const& p
    	, int options = piece_picker::rarest_first)
    {
    	const std::vector<int> empty_vector;
    	std::vector<piece_block> picked = pick_pieces(p, "*******", 1, 0, 0
    		, options, empty_vector);
    	if (picked.empty()) return -1;
    	return picked[0].piece_index;
    }

    TORRENT_TEST(piece_picker)
    {
    	tcp::endpoint endp;
    	piece_picker::downloading_piece st;
    #if TORRENT_USE_ASSERTS
    	tmp0.in_use = true;
    	tmp1.in_use = true;
    	tmp2.in_use = true;
    	tmp3.in_use = true;
    	tmp4.in_use = true;
    	tmp5.in_use = true;
    	tmp6.in_use = true;
    	tmp7.in_use = true;
    	tmp8.in_use = true;
    	tmp9.in_use = true;
    	peer_struct.in_use = true;
    #endif
    	tmp_peer = &tmp1;
    	std::vector<piece_block> picked;
    	boost::shared_ptr<piece_picker> p;
    	const int options = piece_picker::rarest_first;
    	std::pair<int, int> dc;
    	counters pc;

    	print_title("test piece_block");

    	TEST_CHECK(piece_block(0, 0) != piece_block(0, 1));
    	TEST_CHECK(piece_block(0, 0) != piece_block(1, 0));
    	TEST_CHECK(!(piece_block(0, 0) != piece_block(0, 0)));

    	TEST_CHECK(!(piece_block(0, 0) == piece_block(0, 1)));

relevance 2 | ../test/test_storage.cpp:490 | split this test up into smaller parts

## split this test up into smaller parts

#### ../test/test_storage.cpp:490

    	p.path = test_path;
    	p.pool = &fp;
    	p.mode = storage_mode;

    	boost::shared_ptr<void> dummy;
    	boost::shared_ptr<piece_manager> pm = boost::make_shared<piece_manager>(new default_storage(p), dummy, &fs);
    	libtorrent::mutex lock;

    	bool done = false;
    	bdecode_node frd;
    	std::vector<std::string> links;
    	io.async_check_fastresume(pm.get(), &frd, links
    		, boost::bind(&on_check_resume_data, _1, &done));
    	io.submit_jobs();
    	ios.reset();
    	run_until(ios, done);

    	io.set_num_threads(0);
    }

    void run_test(bool unbuffered)
    {
    	std::string test_path = current_working_directory();
    	std::cerr << "\n=== " << test_path << " ===\n" << std::endl;

    	boost::shared_ptr<torrent_info> info;

    	buf_ptr piece0 = new_piece(piece_size);
    	buf_ptr piece1 = new_piece(piece_size);
    	buf_ptr piece2 = new_piece(piece_size);
    	buf_ptr piece3 = new_piece(piece_size);

    	{
    	error_code ec;
    	remove_all(combine_path(test_path, "temp_storage"), ec);
    	if (ec && ec != boost::system::errc::no_such_file_or_directory)
    		std::cerr << "remove_all '" << combine_path(test_path, "temp_storage")
    		<< "': " << ec.message() << std::endl;
    	file_storage fs;
    	fs.add_file("temp_storage/test1.tmp", 17);
    	fs.add_file("temp_storage/test2.tmp", 612);
    	fs.add_file("temp_storage/test3.tmp", 0);
    	fs.add_file("temp_storage/test4.tmp", 0);
    	fs.add_file("temp_storage/test5.tmp", 3253);
    	fs.add_file("temp_storage/test6.tmp", 841);
    	const int last_file_size = 4 * piece_size - fs.total_size();
    	fs.add_file("temp_storage/test7.tmp", last_file_size);

    	// File layout
    	// +-+--+++-------+-------+----------------------------------------------------------------------------------------+
    	// |1| 2||| file5 | file6 | file7                                                                                  |

relevance 2 | ../src/alert.cpp:1474 | the salt here is allocated on the heap. It would be nice to allocate in in the stack_allocator

## the salt here is allocated on the heap. It would be nice to allocate in in the stack_allocator

#### ../src/alert.cpp:1474

    			, operation_names[op]
    			, error.value()
    			, convert_from_native(error.message()).c_str());
    		return msg;
    	}

    	dht_immutable_item_alert::dht_immutable_item_alert(aux::stack_allocator&
    		, sha1_hash const& t, entry const& i)
    		: target(t), item(i)
    	{}

    	std::string dht_immutable_item_alert::message() const
    	{
    		char msg[1050];
    		snprintf(msg, sizeof(msg), "DHT immutable item %s [ %s ]"
    			, to_hex(target.to_string()).c_str()
    			, item.to_string().c_str());
    		return msg;
    	}

    	dht_mutable_item_alert::dht_mutable_item_alert(aux::stack_allocator&
    		, boost::array<char, 32> k
    		, boost::array<char, 64> sig
    		, boost::uint64_t sequence
    		, std::string const& s
    		, entry const& i
    		, bool a)
    		: key(k), signature(sig), seq(sequence), salt(s), item(i), authoritative(a)
    	{}

    	std::string dht_mutable_item_alert::message() const
    	{
    		char msg[1050];
    		snprintf(msg, sizeof(msg), "DHT mutable item (key=%s salt=%s seq=%" PRId64 " %s) [ %s ]"
    			, to_hex(std::string(&key[0], 32)).c_str()
    			, salt.c_str()
    			, seq
    			, authoritative ? "auth" : "non-auth"
    			, item.to_string().c_str());
    		return msg;
    	}

    	dht_put_alert::dht_put_alert(aux::stack_allocator&, sha1_hash const& t, int n)
    		: target(t)
    		, seq(0)
    		, num_success(n)
    	{}

    	dht_put_alert::dht_put_alert(aux::stack_allocator&
    		, boost::array<char, 32> key
    		, boost::array<char, 64> sig

relevance 2 | ../src/alert_manager.cpp:90 | keep a count of the number of threads waiting. Only if it's > 0 notify them

## keep a count of the number of threads waiting. Only if it's > 0 notify them

#### ../src/alert_manager.cpp:90

    		return NULL;
    	}

    	void alert_manager::maybe_notify(alert* a, mutex::scoped_lock& lock)
    	{
    		if (a->type() == save_resume_data_failed_alert::alert_type
    			|| a->type() == save_resume_data_alert::alert_type)
    			++m_num_queued_resume;

    		if (m_alerts[m_generation].size() == 1)
    		{
    			lock.unlock();

    			// we just posted to an empty queue. If anyone is waiting for
    			// alerts, we need to notify them. Also (potentially) call the
    			// user supplied m_notify callback to let the client wake up its
    			// message loop to poll for alerts.
    			if (m_notify) m_notify();

    			m_condition.notify_all();
    		}
    		else
    		{
    			lock.unlock();
    		}

    #ifndef TORRENT_DISABLE_EXTENSIONS
    		for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
    			, end(m_ses_extensions.end()); i != end; ++i)
    		{
    			(*i)->on_alert(a);
    		}
    #endif
    	}

    #ifndef TORRENT_NO_DEPRECATE

    	bool alert_manager::maybe_dispatch(alert const& a)
    	{
    		if (m_dispatch)
    		{
    			m_dispatch(a.clone());
    			return true;
    		}
    		return false;
    	}

    #ifdef __GNUC__
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"

relevance 2 | ../src/block_cache.cpp:1708 | turn these return values into enums returns -1: block not in cache -2: out of memory

## turn these return values into enums returns -1: block not in cache -2: out of memory

#### ../src/block_cache.cpp:1708

    			else
    			{
    				TORRENT_PIECE_ASSERT(!p.blocks[k].dirty, &p);
    				TORRENT_PIECE_ASSERT(!p.blocks[k].pending, &p);
    				TORRENT_PIECE_ASSERT(p.blocks[k].refcount == 0, &p);
    			}
    			num_refcount += p.blocks[k].refcount;
    		}
    		TORRENT_PIECE_ASSERT(num_blocks == p.num_blocks, &p);
    		TORRENT_PIECE_ASSERT(num_pending <= p.refcount, &p);
    		TORRENT_PIECE_ASSERT(num_refcount == p.refcount, &p);
    		TORRENT_PIECE_ASSERT(num_dirty == p.num_dirty, &p);
    	}
    	TORRENT_ASSERT(m_read_cache_size == cached_read_blocks);
    	TORRENT_ASSERT(m_write_cache_size == cached_write_blocks);
    	TORRENT_ASSERT(m_pinned_blocks == num_pinned);
    	TORRENT_ASSERT(m_write_cache_size + m_read_cache_size <= in_use());
    }
    #endif

    int block_cache::copy_from_piece(cached_piece_entry* const pe
    	, disk_io_job* const j
    	, bool const expect_no_fail)
    {
    	INVARIANT_CHECK;
    	TORRENT_UNUSED(expect_no_fail);

    	TORRENT_PIECE_ASSERT(j->buffer.disk_block == 0, pe);
    	TORRENT_PIECE_ASSERT(pe->in_use, pe);

    	// copy from the cache and update the last use timestamp
    	int block = j->d.io.offset / block_size();
    	int block_offset = j->d.io.offset & (block_size()-1);
    	int buffer_offset = 0;
    	int size = j->d.io.buffer_size;
    	int const blocks_to_read = block_offset > 0 && (size > block_size() - block_offset) ? 2 : 1;
    	TORRENT_PIECE_ASSERT(size <= block_size(), pe);
    	int const start_block = block;

    #if TORRENT_USE_ASSERTS
    	int const piece_size = j->storage->files()->piece_size(j->piece);
    	int const blocks_in_piece = (piece_size + block_size() - 1) / block_size();
    	TORRENT_PIECE_ASSERT(start_block < blocks_in_piece, pe);
    #endif

    	// if there's no buffer, we don't have this block in
    	// the cache, and we're not currently reading it in either
    	// since it's not pending

    	if (inc_block_refcount(pe, start_block, ref_reading) == false)

relevance 2 | ../src/escape_string.cpp:209 | this should probably be moved into string_util.cpp

## this should probably be moved into string_util.cpp

#### ../src/escape_string.cpp:209

    		}
    		return false;
    	}

    	void convert_path_to_posix(std::string& path)
    	{
    		for (std::string::iterator i = path.begin()
    			, end(path.end()); i != end; ++i)
    			if (*i == '\\') *i = '/';
    	}

    #ifdef TORRENT_WINDOWS
    	void convert_path_to_windows(std::string& path)
    	{
    		for (std::string::iterator i = path.begin()
    			, end(path.end()); i != end; ++i)
    			if (*i == '/') *i = '\\';
    	}
    #endif

    	std::string read_until(char const*& str, char delim, char const* end)
    	{
    		TORRENT_ASSERT(str <= end);

    		std::string ret;
    		while (str != end && *str != delim)
    		{
    			ret += *str;
    			++str;
    		}
    		// skip the delimiter as well
    		while (str != end && *str == delim) ++str;
    		return ret;
    	}

    	std::string maybe_url_encode(std::string const& url)
    	{
    		std::string protocol, host, auth, path;
    		int port;
    		error_code ec;
    		boost::tie(protocol, auth, host, port, path) = parse_url_components(url, ec);
    		if (ec) return url;

    		// first figure out if this url contains unencoded characters
    		if (!need_encoding(path.c_str(), path.size()))
    			return url;

    		char msg[TORRENT_MAX_PATH*4];
    		snprintf(msg, sizeof(msg), "%s://%s%s%s%s%s%s", protocol.c_str(), auth.c_str()
    			, auth.empty()?"":"@", host.c_str()
    			, port == -1 ? "" : ":"

relevance 2 | ../src/file.cpp:570 | test this on a FAT volume to see what error we get!

## test this on a FAT volume to see what error we get!

#### ../src/file.cpp:570

    		}

    		// fall back to making a copy

    #else

    		std::string n_exist = convert_to_native(file);
    		std::string n_link = convert_to_native(link);

    		// assume posix's link() function exists
    		int ret = ::link(n_exist.c_str(), n_link.c_str());

    		if (ret == 0)
    		{
    			ec.clear();
    			return;
    		}

    		// most errors are passed through, except for the ones that indicate that
    		// hard links are not supported and require a copy.
    		if (errno != EMLINK || errno != EXDEV)
    		{
    			// some error happened, report up to the caller
    			ec.assign(errno, system_category());
    			return;
    		}

    		// fall back to making a copy

    #endif

    		// if we get here, we should copy the file
    		copy_file(file, link, ec);
    	}

    	bool is_directory(std::string const& f, error_code& ec)
    	{
    		ec.clear();
    		error_code e;
    		file_status s;
    		stat_file(f, &s, e);
    		if (!e && s.mode & file_status::directory) return true;
    		ec = e;
    		return false;
    	}

    	void recursive_copy(std::string const& old_path, std::string const& new_path, error_code& ec)
    	{
    		TORRENT_ASSERT(!ec);
    		if (is_directory(old_path, ec))
    		{

relevance 2 | ../src/http_tracker_connection.cpp:385 | returning a bool here is redundant. Instead this function should return the peer_entry

## returning a bool here is redundant. Instead this function should return the peer_entry

#### ../src/http_tracker_connection.cpp:385

    		}
    		else
    		{
    			std::list<address> ip_list;
    			if (m_tracker_connection)
    			{
    				error_code ignore;
    				std::vector<tcp::endpoint> const& epts = m_tracker_connection->endpoints();
    				for (std::vector<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, resp);
    		}
    		close();
    	}

    	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 = errors::invalid_peer_dict;
    			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 = errors::invalid_tracker_response;
    			return false;
    		}
    		ret.hostname = i.string_value();

    		// extract port
    		i = info.dict_find_int("port");
    		if (i == 0)

relevance 2 | ../src/instantiate_connection.cpp:43 | peer_connection and tracker_connection should probably be flags

## peer_connection and tracker_connection should probably be flags

#### ../src/instantiate_connection.cpp:43

relevance 2 | ../src/instantiate_connection.cpp:44 | move this function into libtorrent::aux namespace

## move this function into libtorrent::aux namespace

#### ../src/instantiate_connection.cpp:44

    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    */

    #include "libtorrent/socket.hpp"
    #include "libtorrent/session_settings.hpp"
    #include "libtorrent/socket_type.hpp"
    #include "libtorrent/utp_socket_manager.hpp"
    #include "libtorrent/instantiate_connection.hpp"
    #include <boost/shared_ptr.hpp>
    #include <stdexcept>

    namespace libtorrent
    {
    	bool instantiate_connection(io_service& ios
    		, aux::proxy_settings const& ps, socket_type& s
    		, void* ssl_context
    		, utp_socket_manager* sm
    		, bool peer_connection
    		, bool tracker_connection)
    	{
    #ifndef TORRENT_USE_OPENSSL
    		TORRENT_UNUSED(ssl_context);
    #endif

    		if (sm)
    		{
    			utp_stream* str;
    #ifdef TORRENT_USE_OPENSSL
    			if (ssl_context)
    			{
    				s.instantiate<ssl_stream<utp_stream> >(ios, ssl_context);
    				str = &s.get<ssl_stream<utp_stream> >()->next_layer();
    			}
    			else
    #endif
    			{
    				s.instantiate<utp_stream>(ios);
    				str = s.get<utp_stream>();
    			}
    			str->set_impl(sm->new_utp_socket(str));
    		}
    #if TORRENT_USE_I2P
    		else if (ps.type == settings_pack::i2p_proxy)
    		{

relevance 2 | ../src/peer_connection.cpp:2386 | this should probably be based on time instead of number of request messages. For a very high throughput connection, 300 may be a legitimate number of requests to have in flight when getting choked

## this should probably be based on time instead of number of request messages. For a very high throughput connection, 300 may be a legitimate number of requests to have in flight when getting choked

#### ../src/peer_connection.cpp:2386

    				, "piece: %d s: %d l: %d invalid request"
    				, r.piece , r.start , r.length);
    #endif

    			write_reject_request(r);
    			++m_num_invalid_requests;

    			if (t->alerts().should_post<invalid_request_alert>())
    			{
    				// msvc 12 appears to deduce the rvalue reference template
    				// incorrectly for bool temporaries. So, create a dummy instance
    				bool peer_interested = bool(m_peer_interested);
    				t->alerts().emplace_alert<invalid_request_alert>(
    					t->get_handle(), m_remote, m_peer_id, r
    					, t->has_piece_passed(r.piece), peer_interested, false);
    			}

    			// every ten invalid request, remind the peer that it's choked
    			if (!m_peer_interested && m_num_invalid_requests % 10 == 0 && m_choked)
    			{
    				if (m_num_invalid_requests > 300 && !m_peer_choked
    					&& can_disconnect(errors::too_many_requests_when_choked))
    				{
    					disconnect(errors::too_many_requests_when_choked, op_bittorrent, 2);
    					return;
    				}
    #ifndef TORRENT_DISABLE_LOGGING
    				peer_log(peer_log_alert::outgoing_message, "CHOKE");
    #endif
    				write_choke();
    			}

    			return;
    		}

    		// if we have choked the client
    		// ignore the request
    		const int blocks_per_piece = static_cast<int>(
    			(t->torrent_file().piece_length() + t->block_size() - 1) / t->block_size());

    		// disconnect peers that downloads more than foo times an allowed
    		// fast piece
    		if (m_choked && fast_idx != -1 && m_accept_fast_piece_cnt[fast_idx] >= 3 * blocks_per_piece
    			&& can_disconnect(errors::too_many_requests_when_choked))
    		{
    			disconnect(errors::too_many_requests_when_choked, op_bittorrent, 2);
    			return;
    		}

    		if (m_choked && fast_idx == -1)
    		{

relevance 2 | ../src/peer_connection.cpp:3132 | since we throw away the queue entry once we issue the disk job, this may happen. Instead, we should keep the queue entry around, mark it as having been requested from disk and once the disk job comes back, discard it if it has been cancelled. Maybe even be able to cancel disk jobs?

## since we throw away the queue entry once we issue the disk job, this may happen. Instead, we should keep the queue entry around, mark it as having been requested from disk and once the disk job comes back, discard it if it has been cancelled. Maybe even be able to cancel disk jobs?

#### ../src/peer_connection.cpp:3132

    		std::vector<peer_request>::iterator i
    			= std::find(m_requests.begin(), m_requests.end(), r);

    		if (i != m_requests.end())
    		{
    			m_counters.inc_stats_counter(counters::cancelled_piece_requests);
    			m_requests.erase(i);

    			if (m_requests.empty())
    				m_counters.inc_stats_counter(counters::num_peers_up_requests, -1);

    #ifndef TORRENT_DISABLE_LOGGING
    			peer_log(peer_log_alert::outgoing_message, "REJECT_PIECE", "piece: %d s: %x l: %x cancelled"
    				, r.piece , r.start , r.length);
    #endif
    			write_reject_request(r);
    		}
    		else
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			peer_log(peer_log_alert::info, "INVALID_CANCEL", "got cancel not in the queue");
    #endif
    		}
    	}

    	// -----------------------------
    	// --------- DHT PORT ----------
    	// -----------------------------

    	void peer_connection::incoming_dht_port(int listen_port)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    #ifndef TORRENT_DISABLE_LOGGING
    		peer_log(peer_log_alert::incoming_message, "DHT_PORT", "p: %d", listen_port);
    #endif
    #ifndef TORRENT_DISABLE_DHT
    		m_ses.add_dht_node(udp::endpoint(
    			m_remote.address(), listen_port));
    #else
    		TORRENT_UNUSED(listen_port);
    #endif
    	}

    	// -----------------------------
    	// --------- HAVE ALL ----------
    	// -----------------------------

    	void peer_connection::incoming_have_all()

relevance 2 | ../src/peer_connection.cpp:4819 | use a deadline_timer for timeouts. Don't rely on second_tick()! Hook this up to connect timeout as well. This would improve performance because of less work in second_tick(), and might let use remove ticking entirely eventually

## use a deadline_timer for timeouts. Don't rely on second_tick()! Hook this up to connect timeout as well. This would improve performance because of less work in second_tick(), and might let use remove ticking entirely eventually

#### ../src/peer_connection.cpp:4819

    				connect_timeout += 20;
    #endif

    			if (d > seconds(connect_timeout)
    				&& can_disconnect(errors::timed_out))
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				peer_log(peer_log_alert::info, "CONNECT_FAILED", "waited %d seconds"
    					, int(total_seconds(d)));
    #endif
    				connect_failed(errors::timed_out);
    				return;
    			}
    		}

    		// if we can't read, it means we're blocked on the rate-limiter
    		// or the disk, not the peer itself. In this case, don't blame
    		// the peer and disconnect it
    		bool may_timeout = (m_channel_state[download_channel] & peer_info::bw_network) != 0;

    		if (may_timeout && d > seconds(timeout()) && !m_connecting && m_reading_bytes == 0
    			&& can_disconnect(errors::timed_out_inactivity))
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			peer_log(peer_log_alert::info, "LAST_ACTIVITY", "%d seconds ago"
    				, int(total_seconds(d)));
    #endif
    			disconnect(errors::timed_out_inactivity, op_bittorrent);
    			return;
    		}

    		// do not stall waiting for a handshake
    		int timeout = m_settings.get_int (settings_pack::handshake_timeout);
    #if TORRENT_USE_I2P
    		timeout *= is_i2p(*m_socket) ? 4 : 1;
    #endif
    		if (may_timeout
    			&& !m_connecting
    			&& in_handshake()
    			&& d > seconds(timeout))
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			peer_log(peer_log_alert::info, "NO_HANDSHAKE", "waited %d seconds"
    				, int(total_seconds(d)));
    #endif
    			disconnect(errors::timed_out_no_handshake, op_bittorrent);
    			return;
    		}

    		// disconnect peers that we unchoked, but they didn't send a request in
    		// the last 60 seconds, and we haven't been working on servicing a request

relevance 2 | ../src/peer_list.cpp:507 | it would be nice if there was a way to iterate over these torrent_peer objects in the order they are allocated in the pool instead. It would probably be more efficient

## it would be nice if there was a way to iterate over these torrent_peer objects in the order they are allocated in the pool instead. It would probably be more efficient

#### ../src/peer_list.cpp:507

    		, int session_time, torrent_state* state)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    		const int candidate_count = 10;
    		peers.reserve(candidate_count);

    		int erase_candidate = -1;

    		if (m_finished != state->is_finished)
    			recalculate_connect_candidates(state);

    		external_ip const& external = *state->ip;
    		int external_port = state->port;

    		if (m_round_robin >= int(m_peers.size())) m_round_robin = 0;

    		int max_peerlist_size = state->max_peerlist_size;

    		for (int iterations = (std::min)(int(m_peers.size()), 300);
    			iterations > 0; --iterations)
    		{
    			++state->loop_counter;

    			if (m_round_robin >= int(m_peers.size())) m_round_robin = 0;

    			torrent_peer& pe = *m_peers[m_round_robin];
    			TORRENT_ASSERT(pe.in_use);
    			int current = m_round_robin;

    			// if the number of peers is growing large
    			// we need to start weeding.

    			if (int(m_peers.size()) >= max_peerlist_size * 0.95
    				&& max_peerlist_size > 0)
    			{
    				if (is_erase_candidate(pe)
    					&& (erase_candidate == -1
    						|| !compare_peer_erase(*m_peers[erase_candidate], pe)))
    				{
    					if (should_erase_immediately(pe))
    					{
    						if (erase_candidate > current) --erase_candidate;
    						erase_peer(m_peers.begin() + current, state);
    						continue;
    					}
    					else
    					{
    						erase_candidate = current;
    					}

relevance 2 | ../src/piece_picker.cpp:1977 | make the 2048 limit configurable

## make the 2048 limit configurable

#### ../src/piece_picker.cpp:1977

    	// returned block picks.
    	boost::uint32_t piece_picker::pick_pieces(bitfield const& pieces
    		, std::vector<piece_block>& interesting_blocks, int num_blocks
    		, int prefer_contiguous_blocks, torrent_peer* peer
    		, int options, std::vector<int> const& suggested_pieces
    		, int num_peers
    		, counters& pc
    		) const
    	{
    		TORRENT_ASSERT(peer == 0 || peer->in_use);
    		boost::uint32_t ret = 0;

    		// prevent the number of partial pieces to grow indefinitely
    		// make this scale by the number of peers we have. For large
    		// scale clients, we would have more peers, and allow a higher
    		// threshold for the number of partials
    		// deduct pad files because they case partial pieces which are OK
    		// the second condition is to make sure we cap the number of partial
    		// _bytes_. The larger the pieces are, the fewer partial pieces we want.
    		// 2048 corresponds to 32 MiB
    		const int num_partials = int(m_downloads[piece_pos::piece_downloading].size())
    			- m_num_pad_files;
    		if (num_partials > num_peers * 3 / 2
    			|| num_partials * m_blocks_per_piece > 2048)
    		{
    			// if we have too many partial pieces, prioritize completing
    			// them. In order for this to have an affect, also disable
    			// prefer whole pieces (otherwise partial pieces would be de-prioritized)
    			options |= prioritize_partials;
    			prefer_contiguous_blocks = 0;

    			ret |= picker_log_alert::partial_ratio;
    		}

    		if (prefer_contiguous_blocks) ret |= picker_log_alert::prefer_contiguous;

    		// only one of rarest_first and sequential can be set.
    		TORRENT_ASSERT(((options & rarest_first) ? 1 : 0)
    			+ ((options & sequential) ? 1 : 0) <= 1);
    #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
    		TORRENT_PIECE_PICKER_INVARIANT_CHECK;
    #endif
    		TORRENT_ASSERT(num_blocks > 0);
    		TORRENT_ASSERT(pieces.size() == m_piece_map.size());

    		TORRENT_ASSERT(!m_priority_boundries.empty() || m_dirty);

    		// this will be filled with blocks that we should not request
    		// unless we can't find num_blocks among the other ones.
    		std::vector<piece_block> backup_blocks;
    		std::vector<piece_block> backup_blocks2;

relevance 2 | ../src/piece_picker.cpp:2608 | the first_block returned here is the largest free range, not the first-fit range, which would be better

## the first_block returned here is the largest free range, not the first-fit range, which would be better

#### ../src/piece_picker.cpp:2608

    			, end(m_block_info.end()); i != end; ++i)
    		{
    			TORRENT_ASSERT(i->peer == 0 || static_cast<torrent_peer*>(i->peer)->in_use);
    		}
    	}
    #endif

    	void piece_picker::clear_peer(torrent_peer* peer)
    	{
    		for (std::vector<block_info>::iterator i = m_block_info.begin()
    			, end(m_block_info.end()); i != end; ++i)
    		{
    			if (i->peer == peer) i->peer = 0;
    		}
    	}

    	// the first bool is true if this is the only peer that has requested and downloaded
    	// blocks from this piece.
    	// the second bool is true if this is the only active peer that is requesting
    	// and downloading blocks from this piece. Active means having a connection.
    	boost::tuple<bool, bool, int, int> piece_picker::requested_from(
    		piece_picker::downloading_piece const& p
    		, int num_blocks_in_piece, torrent_peer* peer) const
    	{
    		bool exclusive = true;
    		bool exclusive_active = true;
    		int contiguous_blocks = 0;
    		int max_contiguous = 0;
    		int first_block = 0;
    		block_info const* binfo = blocks_for_piece(p);
    		for (int j = 0; j < num_blocks_in_piece; ++j)
    		{
    			piece_picker::block_info const& info = binfo[j];
    			TORRENT_ASSERT(info.peer == 0 || static_cast<torrent_peer*>(info.peer)->in_use);
    			TORRENT_ASSERT(info.piece_index == p.index);
    			if (info.state == piece_picker::block_info::state_none)
    			{
    				++contiguous_blocks;
    				continue;
    			}
    			if (contiguous_blocks > max_contiguous)
    			{
    				max_contiguous = contiguous_blocks;
    				first_block = j - contiguous_blocks;
    			}
    			contiguous_blocks = 0;
    			if (info.peer != peer)
    			{
    				exclusive = false;
    				if (info.state == piece_picker::block_info::state_requested
    					&& info.peer != 0)

relevance 2 | ../src/piece_picker.cpp:3386 | it would be nice if this could be folded into lock_piece() the main distinction is that this also maintains the m_num_passed counter and the passed_hash_check member Is there ever a case where we call write filed without also locking the piece? Perhaps write_failed() should imply locking it.

## it would be nice if this could be folded into lock_piece() the main distinction is that this also maintains the m_num_passed counter and the passed_hash_check member Is there ever a case where we call write filed without also locking the piece? Perhaps write_failed() should imply locking it.

#### ../src/piece_picker.cpp:3386

    		int state = m_piece_map[piece].download_queue();
    		if (state == piece_pos::piece_open) return;
    		std::vector<downloading_piece>::iterator i = find_dl_piece(state, piece);
    		if (i == m_downloads[state].end()) return;

    		TORRENT_ASSERT(i->passed_hash_check == false);
    		if (i->passed_hash_check)
    		{
    			// it's not clear why this would happen,
    			// but it seems reasonable to not break the
    			// accounting over it.
    			i->passed_hash_check = false;
    			TORRENT_ASSERT(m_num_passed > 0);
    			--m_num_passed;
    		}

    		// prevent this piece from being picked until it's restored
    		i->locked = true;
    	}

    	void piece_picker::write_failed(piece_block block)
    	{
    		TORRENT_PIECE_PICKER_INVARIANT_CHECK;

    #if TORRENT_USE_INVARIANT_CHECKS
    		check_piece_state();
    #endif

    #ifdef TORRENT_PICKER_LOG
    		std::cerr << "[" << this << "] " << "write_failed( {" << block.piece_index << ", " << block.block_index << "} )" << std::endl;
    #endif

    		int state = m_piece_map[block.piece_index].download_queue();
    		if (state == piece_pos::piece_open) return;
    		std::vector<downloading_piece>::iterator i = find_dl_piece(state, block.piece_index);
    		if (i == m_downloads[state].end()) return;

    		block_info* binfo = blocks_for_piece(*i);
    		block_info& info = binfo[block.block_index];
    		TORRENT_ASSERT(&info >= &m_block_info[0]);
    		TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
    		TORRENT_ASSERT(info.piece_index == block.piece_index);
    		TORRENT_ASSERT(info.state == block_info::state_writing);
    		TORRENT_ASSERT(info.num_peers == 0);

    		TORRENT_ASSERT(i->writing > 0);
    		TORRENT_ASSERT(info.state == block_info::state_writing);

    		if (info.state == block_info::state_finished) return;
    		if (info.state == block_info::state_writing) --i->writing;

relevance 2 | ../src/receive_buffer.cpp:209 | should this take a boost::array<..., 2> instead? it could return the number of buffers added, just like reserve.

## should this take a boost::array<..., 2> instead? it could return the number of buffers added, just like reserve.

#### ../src/receive_buffer.cpp:209

    	int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()) - m_recv_start);
    	return buffer::const_interval(&m_recv_buffer[0] + m_recv_start
    		, &m_recv_buffer[0] + m_recv_start + rcv_pos);
    }

    #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
    buffer::interval receive_buffer::mutable_buffer()
    {
    	if (m_recv_buffer.empty())
    	{
    		TORRENT_ASSERT(m_recv_pos == 0);
    		return buffer::interval(0,0);
    	}
    	TORRENT_ASSERT(!m_disk_recv_buffer);
    	TORRENT_ASSERT(m_disk_recv_buffer_size == 0);
    	int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()));
    	return buffer::interval(&m_recv_buffer[0] + m_recv_start
    		, &m_recv_buffer[0] + m_recv_start + rcv_pos);
    }

    void receive_buffer::mutable_buffers(std::vector<boost::asio::mutable_buffer>& vec, int const bytes)
    {
    	namespace asio = boost::asio;

    	// bytes is the number of bytes we just received, and m_recv_pos has
    	// already been adjusted for these bytes. The receive pos immediately
    	// before we received these bytes was (m_recv_pos - bytes)

    	int const last_recv_pos = m_recv_pos - bytes;
    	TORRENT_ASSERT(bytes <= m_recv_pos);

    	// the number of bytes in the current packet that are being received into a
    	// regular receive buffer (as opposed to a disk cache buffer)
    	int const regular_buf_size = regular_buffer_size();

    	TORRENT_ASSERT(regular_buf_size >= 0);
    	if (!m_disk_recv_buffer || regular_buf_size >= m_recv_pos)
    	{
    		// we just received into a regular disk buffer
    		vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start
    			+ last_recv_pos, bytes));
    	}
    	else if (last_recv_pos >= regular_buf_size)
    	{
    		// we only received into a disk buffer
    		vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get()
    			+ last_recv_pos - regular_buf_size, bytes));
    	}
    	else
    	{
    		// we received into a regular and a disk buffer

relevance 2 | ../src/session_impl.cpp:455 | is there a reason not to move all of this into init()? and just post it to the io_service?

## is there a reason not to move all of this into init()? and just post it to the io_service?

#### ../src/session_impl.cpp:455

    		m_udp_socket.set_rate_limit(m_settings.get_int(settings_pack::dht_upload_rate_limit));

    		m_udp_socket.subscribe(&m_utp_socket_manager);
    		m_udp_socket.subscribe(this);
    		m_udp_socket.subscribe(&m_tracker_manager);

    #ifdef TORRENT_USE_OPENSSL
    		m_ssl_udp_socket.subscribe(&m_ssl_utp_socket_manager);
    		m_ssl_udp_socket.subscribe(this);
    #endif

    		error_code ec;
    		m_listen_interface = tcp::endpoint(address_v4::any(), 0);
    		TORRENT_ASSERT_VAL(!ec, ec);

    		update_time_now();
    	}

    	// This function is called by the creating thread, not in the message loop's
    	// / io_service thread.
    	void session_impl::start_session(settings_pack const& pack)
    	{
    		if (pack.has_val(settings_pack::alert_mask))
    		{
    			m_alerts.set_alert_mask(pack.get_int(settings_pack::alert_mask));
    		}

    #ifndef TORRENT_DISABLE_LOGGING
    		session_log("start session");
    #endif

    		error_code ec;
    #ifdef TORRENT_USE_OPENSSL
    		m_ssl_ctx.set_verify_mode(boost::asio::ssl::context::verify_none, ec);
    #if BOOST_VERSION >= 104700
    #if OPENSSL_VERSION_NUMBER >= 0x90812f
    		aux::openssl_set_tlsext_servername_callback(m_ssl_ctx.native_handle()
    			, servername_callback);
    		aux::openssl_set_tlsext_servername_arg(m_ssl_ctx.native_handle(), this);
    #endif // OPENSSL_VERSION_NUMBER
    #endif // BOOST_VERSION
    #endif

    #ifndef TORRENT_DISABLE_DHT
    		m_next_dht_torrent = m_torrents.begin();
    #endif
    		m_next_lsd_torrent = m_torrents.begin();
    		m_tcp_mapping[0] = -1;
    		m_tcp_mapping[1] = -1;
    		m_udp_mapping[0] = -1;
    		m_udp_mapping[1] = -1;

relevance 2 | ../src/session_impl.cpp:1974 | the udp socket(s) should be using the same generic mechanism and not be restricted to a single one we should open a one listen socket for each entry in the listen_interfaces list

## the udp socket(s) should be using the same generic mechanism and not be restricted to a single one we should open a one listen socket for each entry in the listen_interfaces list

#### ../src/session_impl.cpp:1974

    				}
    #endif // TORRENT_USE_OPENSSL
    			}
    #endif // TORRENT_USE_IPV6

    			// set our main IPv4 and IPv6 interfaces
    			// used to send to the tracker
    			std::vector<ip_interface> ifs = enum_net_interfaces(m_io_service, ec);
    			for (std::vector<ip_interface>::const_iterator i = ifs.begin()
    					, end(ifs.end()); i != end; ++i)
    			{
    				address const& addr = i->interface_address;
    				if (addr.is_v6() && !is_local(addr) && !is_loopback(addr))
    					m_ipv6_interface = tcp::endpoint(addr, m_listen_interface.port());
    				else if (addr.is_v4() && !is_local(addr) && !is_loopback(addr))
    					m_ipv4_interface = tcp::endpoint(addr, m_listen_interface.port());
    			}
    		}
    		else
    		{
    			for (int i = 0; i < m_listen_interfaces.size(); ++i)
    			{
    				std::string const& device = m_listen_interfaces[i].first;
    				int port = m_listen_interfaces[i].second;

    				int num_device_fails = 0;

    #if TORRENT_USE_IPV6
    				const int first_family = 0;
    #else
    				const int first_family = 1;
    #endif
    				boost::asio::ip::tcp protocol[]
    					= { boost::asio::ip::tcp::v6(), boost::asio::ip::tcp::v4() };

    				for (int address_family = first_family; address_family < 2; ++address_family)
    				{
    					error_code err;
    					address test_family = address::from_string(device.c_str(), err);
    					if (!err
    						&& test_family.is_v4() != address_family
    						&& !is_any(test_family))
    						continue;

    					listen_socket_t s = setup_listener(device, protocol[address_family]
    						, port, flags, ec);

    					if (ec == error_code(boost::system::errc::no_such_device, generic_category()))
    					{
    						++num_device_fails;
    						continue;

relevance 2 | ../src/session_impl.cpp:3650 | make a list for torrents that want to be announced on the DHT so we don't have to loop over all torrents, just to find the ones that want to announce

## make a list for torrents that want to be announced on the DHT so we don't have to loop over all torrents, just to find the ones that want to announce

#### ../src/session_impl.cpp:3650

    		if (!m_dht_torrents.empty())
    		{
    			boost::shared_ptr<torrent> t;
    			do
    			{
    				t = m_dht_torrents.front().lock();
    				m_dht_torrents.pop_front();
    			} while (!t && !m_dht_torrents.empty());

    			if (t)
    			{
    				t->dht_announce();
    				return;
    			}
    		}
    		if (m_torrents.empty()) return;

    		if (m_next_dht_torrent == m_torrents.end())
    			m_next_dht_torrent = m_torrents.begin();
    		m_next_dht_torrent->second->dht_announce();
    		++m_next_dht_torrent;
    		if (m_next_dht_torrent == m_torrents.end())
    			m_next_dht_torrent = m_torrents.begin();
    	}
    #endif

    	void session_impl::on_lsd_announce(error_code const& e)
    	{
    #if defined TORRENT_ASIO_DEBUGGING
    		complete_async("session_impl::on_lsd_announce");
    #endif
    		m_stats_counters.inc_stats_counter(counters::on_lsd_counter);
    		TORRENT_ASSERT(is_single_thread());
    		if (e) return;

    		if (m_abort) return;

    #if defined TORRENT_ASIO_DEBUGGING
    		add_outstanding_async("session_impl::on_lsd_announce");
    #endif
    		// announce on local network every 5 minutes
    		int delay = (std::max)(m_settings.get_int(settings_pack::local_service_announce_interval)
    			/ (std::max)(int(m_torrents.size()), 1), 1);
    		error_code ec;
    		m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
    		m_lsd_announce_timer.async_wait(
    			bind(&session_impl::on_lsd_announce, this, _1));

    		if (m_torrents.empty()) return;

    		if (m_next_lsd_torrent == m_torrents.end())

relevance 2 | ../src/session_impl.cpp:6221 | this should be factored into the udp socket, so we only have the code once

## this should be factored into the udp socket, so we only have the code once

#### ../src/session_impl.cpp:6221

    	{
    		return upload_rate_limit(m_local_peer_class);
    	}

    	int session_impl::local_download_rate_limit() const
    	{
    		return download_rate_limit(m_local_peer_class);
    	}

    	int session_impl::upload_rate_limit() const
    	{
    		return upload_rate_limit(m_global_class);
    	}

    	int session_impl::download_rate_limit() const
    	{
    		return download_rate_limit(m_global_class);
    	}
    #endif

    	void session_impl::update_peer_tos()
    	{
    		error_code ec;

    #if TORRENT_USE_IPV6 && defined IPV6_TCLASS
    		if (m_udp_socket.local_endpoint(ec).address().is_v6())
    			m_udp_socket.set_option(traffic_class(m_settings.get_int(settings_pack::peer_tos)), ec);
    		else
    #endif
    			m_udp_socket.set_option(type_of_service(m_settings.get_int(settings_pack::peer_tos)), ec);

    #ifdef TORRENT_USE_OPENSSL
    #if TORRENT_USE_IPV6 && defined IPV6_TCLASS
    		if (m_ssl_udp_socket.local_endpoint(ec).address().is_v6())
    			m_ssl_udp_socket.set_option(traffic_class(m_settings.get_int(settings_pack::peer_tos)), ec);
    		else
    #endif
    			m_ssl_udp_socket.set_option(type_of_service(m_settings.get_int(settings_pack::peer_tos)), ec);
    #endif

    #ifndef TORRENT_DISABLE_LOGGING
    		session_log(">>> SET_TOS [ udp_socket tos: %x e: %s ]"
    			, m_settings.get_int(settings_pack::peer_tos)
    			, ec.message().c_str());
    #endif
    	}

    	void session_impl::update_user_agent()
    	{
    		// replace all occurrences of '\n' with ' '.
    		std::string agent = m_settings.get_str(settings_pack::user_agent);

relevance 2 | ../src/session_impl.cpp:6921 | perhaps DHT logging should be disabled by TORRENT_DISABLE_LOGGING too

## perhaps DHT logging should be disabled by TORRENT_DISABLE_LOGGING too

#### ../src/session_impl.cpp:6921

    	void session_impl::get_peers(sha1_hash const& ih)
    	{
    		if (!m_alerts.should_post<dht_get_peers_alert>()) return;
    		m_alerts.emplace_alert<dht_get_peers_alert>(ih);
    	}

    	void session_impl::announce(sha1_hash const& ih, address const& addr
    		, int port)
    	{
    		if (!m_alerts.should_post<dht_announce_alert>()) return;
    		m_alerts.emplace_alert<dht_announce_alert>(addr, port, ih);
    	}

    	void session_impl::outgoing_get_peers(sha1_hash const& target
    		, sha1_hash const& sent_target, udp::endpoint const& ep)
    	{
    		if (!m_alerts.should_post<dht_outgoing_get_peers_alert>()) return;
    		m_alerts.emplace_alert<dht_outgoing_get_peers_alert>(target, sent_target, ep);
    	}

    	TORRENT_FORMAT(3,4)
    	void session_impl::log(libtorrent::dht::dht_logger::module_t m, char const* fmt, ...)
    	{
    		if (!m_alerts.should_post<dht_log_alert>()) return;

    		va_list v;
    		va_start(v, fmt);
    		char buf[1024];
    		vsnprintf(buf, sizeof(buf), fmt, v);
    		va_end(v);
    		m_alerts.emplace_alert<dht_log_alert>(static_cast<dht_log_alert::dht_module_t>(m), buf);
    	}

    	void session_impl::log_packet(message_direction_t dir, char const* pkt, int len
    		, udp::endpoint node)
    	{
    		if (!m_alerts.should_post<dht_pkt_alert>()) return;

    		dht_pkt_alert::direction_t d = dir == dht_logger::incoming_message
    			? dht_pkt_alert::incoming : dht_pkt_alert::outgoing;

    		m_alerts.emplace_alert<dht_pkt_alert>(pkt, len, d, node);
    	}

    	bool session_impl::on_dht_request(char const* query, int query_len
    		, dht::msg const& request, entry& response)
    	{
    #ifndef TORRENT_DISABLE_EXTENSIONS
    		if (query_len > max_dht_query_length) return false;

    		for (m_extension_dht_queries_t::iterator i = m_extension_dht_queries.begin();

relevance 2 | ../src/storage.cpp:1127 | we probably need to do this unconditionally in this function. Even if the resume data file appears stale, we need to create these hard links, right?

## we probably need to do this unconditionally in this function. Even if the resume data file appears stale, we need to create these hard links, right?

#### ../src/storage.cpp:1127

    			{
    				ec.ec = errors::mismatching_file_size;
    				ec.file = i;
    				ec.operation = storage_error::none;
    				return false;
    			}

    			if (settings().get_bool(settings_pack::ignore_resume_timestamps)) continue;

    			// allow some slack, because of FAT volumes
    			if (expected_time != 0 &&
    				(file_time > expected_time + 5 * 60 || file_time < expected_time - 5))
    			{
    				ec.ec = errors::mismatching_file_timestamp;
    				ec.file = i;
    				ec.operation = storage_error::stat;
    				return false;
    			}
    		}

    #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
    		if (links)
    		{
    			// if this is a mutable torrent, and we need to pick up some files
    			// from other torrents, do that now. Note that there is an inherent
    			// race condition here. We checked if the files existed on a different
    			// thread a while ago. These files may no longer exist or may have been
    			// moved. If so, we just fail. The user is responsible to not touch
    			// other torrents until a new mutable torrent has been completely
    			// added.
    			int idx = 0;
    			for (std::vector<std::string>::const_iterator i = links->begin();
    				i != links->end(); ++i, ++idx)
    			{
    				if (i->empty()) continue;

    				error_code err;
    				std::string file_path = fs.file_path(idx, m_save_path);
    				hard_link(*i, file_path, err);

    				// if the file already exists, that's not an error

relevance 2 | ../src/storage.cpp:1151 | is this risky? The upper layer will assume we have the whole file. Perhaps we should verify that at least the size of the file is correct

## is this risky? The upper layer will assume we have the whole file. Perhaps we should verify that at least the size of the file is correct

#### ../src/storage.cpp:1151

    		if (links)
    		{
    			// if this is a mutable torrent, and we need to pick up some files
    			// from other torrents, do that now. Note that there is an inherent
    			// race condition here. We checked if the files existed on a different
    			// thread a while ago. These files may no longer exist or may have been
    			// moved. If so, we just fail. The user is responsible to not touch
    			// other torrents until a new mutable torrent has been completely
    			// added.
    			int idx = 0;
    			for (std::vector<std::string>::const_iterator i = links->begin();
    				i != links->end(); ++i, ++idx)
    			{
    				if (i->empty()) continue;

    				error_code err;
    				std::string file_path = fs.file_path(idx, m_save_path);
    				hard_link(*i, file_path, err);

    				// if the file already exists, that's not an error
    				if (!err || err == boost::system::errc::file_exists)
    					continue;

    				ec.ec = err;
    				ec.file = idx;
    				ec.operation = storage_error::hard_link;
    				return false;
    			}
    		}
    #endif // TORRENT_DISABLE_MUTABLE_TORRENTS

    		return true;
    	}

    	int default_storage::move_storage(std::string const& sp, int const flags
    		, storage_error& ec)
    	{
    		int ret = piece_manager::no_error;
    		std::string const save_path = complete(sp);

    		// check to see if any of the files exist
    		file_storage const& f = files();

    		if (flags == fail_if_exist)
    		{
    			file_status s;
    			error_code err;
    			stat_file(save_path, &s, err);
    			if (err != boost::system::errc::no_such_file_or_directory)
    			{
    				// the directory exists, check all the files

relevance 2 | ../src/torrent.cpp:685 | post alert

## post alert

#### ../src/torrent.cpp:685

    		if (new_gauge_state == m_current_gauge_state) return;

    		if (m_current_gauge_state != no_gauge_state)
    			inc_stats_counter(m_current_gauge_state + counters::num_checking_torrents, -1);
    		if (new_gauge_state != no_gauge_state)
    			inc_stats_counter(new_gauge_state + counters::num_checking_torrents, 1);

    		m_current_gauge_state = new_gauge_state;
    	}

    	void torrent::leave_seed_mode(bool skip_checking)
    	{
    		if (!m_seed_mode) return;

    		if (!skip_checking)
    		{
    			// this means the user promised we had all the
    			// files, but it turned out we didn't. This is
    			// an error.

    #ifndef TORRENT_DISABLE_LOGGING
    			debug_log("*** FAILED SEED MODE, rechecking");
    #endif
    		}

    #ifndef TORRENT_DISABLE_LOGGING
    		debug_log("*** LEAVING SEED MODE (%s)"
    			, skip_checking ? "as seed" : "as non-seed");
    #endif
    		m_seed_mode = false;
    		// seed is false if we turned out not
    		// to be a seed after all
    		if (!skip_checking)
    		{
    			m_have_all = false;
    			set_state(torrent_status::downloading);
    			force_recheck();
    		}
    		m_num_verified = 0;
    		m_verified.clear();
    		m_verifying.clear();

    		set_need_save_resume();
    	}

    	void torrent::verified(int piece)
    	{
    		TORRENT_ASSERT(piece < int(m_verified.size()));
    		TORRENT_ASSERT(piece >= 0);
    		TORRENT_ASSERT(m_verified.get_bit(piece) == false);

relevance 2 | ../src/torrent.cpp:1943 | add a unit test where we don't have metadata, connect to a peer that sends a bitfield that's too large, then we get the metadata

## add a unit test where we don't have metadata, connect to a peer that sends a bitfield that's too large, then we get the metadata

#### ../src/torrent.cpp:1943

    			{
    				read_resume_data(m_resume_data->node);
    			}
    		}

    #if TORRENT_USE_ASSERTS
    		m_resume_data_loaded = true;
    #endif

    		construct_storage();

    		if (m_share_mode && valid_metadata())
    		{
    			// in share mode, all pieces have their priorities initialized to 0
    			m_file_priority.clear();
    			m_file_priority.resize(m_torrent_file->num_files(), 0);
    		}

    		// it's important to initialize the peers early, because this is what will
    		// fix up their have-bitmasks to have the correct size
    		if (!m_connections_initialized)
    		{
    			m_connections_initialized = true;
    			// all peer connections have to initialize themselves now that the metadata
    			// is available
    			// copy the peer list since peers may disconnect and invalidate
    			// m_connections as we initialize them
    			std::vector<peer_connection*> peers = m_connections;
    			for (torrent::peer_iterator i = peers.begin();
    				i != peers.end(); ++i)
    			{
    				peer_connection* pc = *i;
    				if (pc->is_disconnecting()) continue;
    				pc->on_metadata_impl();
    				if (pc->is_disconnecting()) continue;
    				pc->init();
    			}
    		}

    		// if we've already loaded file priorities, don't load piece priorities,
    		// they will interfere.
    		if (!m_seed_mode && m_resume_data && m_file_priority.empty())
    		{
    			bdecode_node piece_priority = m_resume_data->node
    				.dict_find_string("piece_priority");

    			if (piece_priority && piece_priority.string_length()
    				== m_torrent_file->num_pieces())
    			{
    				char const* p = piece_priority.string_ptr();
    				for (int i = 0; i < piece_priority.string_length(); ++i)

relevance 2 | ../src/torrent.cpp:5032 | abort lookups this torrent has made via the session host resolver interface

## abort lookups this torrent has made via the session host resolver interface

#### ../src/torrent.cpp:5032

    #endif

    		// disconnect all peers and close all
    		// files belonging to the torrents
    		disconnect_all(errors::torrent_aborted, op_bittorrent);

    		// post a message to the main thread to destruct
    		// the torrent object from there
    		if (m_storage.get())
    		{
    			m_ses.disk_thread().async_stop_torrent(m_storage.get()
    				, boost::bind(&torrent::on_torrent_aborted, shared_from_this()));
    		}
    		else
    		{
    			TORRENT_ASSERT(m_abort);
    			if (alerts().should_post<cache_flushed_alert>())
    				alerts().emplace_alert<cache_flushed_alert>(get_handle());
    		}

    		if (!m_apply_ip_filter)
    		{
    			inc_stats_counter(counters::non_filter_torrents, -1);
    			m_apply_ip_filter = true;
    		}

    		m_allow_peers = false;
    		m_auto_managed = false;
    		update_state_list();
    		for (int i = 0; i < aux::session_interface::num_torrent_lists; ++i)
    		{
    			if (!m_links[i].in_list()) continue;
    			m_links[i].unlink(m_ses.torrent_list(i), i);
    		}
    		// don't re-add this torrent to the state-update list
    		m_state_subscription = false;
    	}

    	void torrent::super_seeding(bool on)
    	{
    		if (on == m_super_seeding) return;

    		m_super_seeding = on;
    		set_need_save_resume();
    		state_updated();

    		if (m_super_seeding) return;

    		// disable super seeding for all peers
    		for (peer_iterator i = begin(); i != end(); ++i)

relevance 2 | ../src/torrent.cpp:8259 | if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)

## if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)

#### ../src/torrent.cpp:8259

    #ifndef TORRENT_DISABLE_LOGGING
    		debug_log("incoming peer (%d)", int(m_connections.size()));
    #endif

    #ifdef TORRENT_DEBUG
    		error_code ec;
    		TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
    #endif

    		TORRENT_ASSERT(p->peer_info_struct() != NULL);

    		// we need to do this after we've added the peer to the peer_list
    		// since that's when the peer is assigned its peer_info object,
    		// which holds the rank
    		if (maybe_replace_peer)
    		{
    			// now, find the lowest rank peer and disconnect that
    			// if it's lower rank than the incoming connection
    			peer_connection* peer = find_lowest_ranking_peer();

    			if (peer && peer->peer_rank() < p->peer_rank())
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				debug_log("CLOSING CONNECTION \"%s\" peer list full (low peer rank) "
    					"connections: %d limit: %d"
    					, print_endpoint(peer->remote()).c_str()
    					, int(m_connections.size())
    					, m_max_connections);
    #endif
    				peer->disconnect(errors::too_many_connections, op_bittorrent);
    				p->peer_disconnected_other();
    			}
    			else
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				debug_log("CLOSING CONNECTION \"%s\" peer list full (low peer rank) "
    					"connections: %d limit: %d"
    					, print_endpoint(p->remote()).c_str()
    					, int(m_connections.size())
    					, m_max_connections);
    #endif
    				p->disconnect(errors::too_many_connections, op_bittorrent);
    				// we have to do this here because from the peer's point of
    				// it wasn't really attached to the torrent, but we do need
    				// to let peer_list know we're removing it
    				remove_peer(p);
    				return false;
    			}
    		}

    #if TORRENT_USE_INVARIANT_CHECKS

relevance 2 | ../src/torrent.cpp:10750 | this should probably be removed

## this should probably be removed

#### ../src/torrent.cpp:10750

    		// now, rarest_pieces is a list of all pieces that are the rarest ones.
    		// and rarest_rarity is the number of peers that have the rarest pieces

    		// if there's only a single peer that doesn't have the rarest piece
    		// it's impossible for us to download one piece and upload it
    		// twice. i.e. we cannot get a positive share ratio
    		if (num_peers - rarest_rarity
    			< settings().get_int(settings_pack::share_mode_target))
    			return;

    		// now, pick one of the rarest pieces to download
    		int pick = random() % rarest_pieces.size();
    		bool was_finished = is_finished();
    		m_picker->set_piece_priority(rarest_pieces[pick], 4);
    		update_gauge();
    		update_peer_interest(was_finished);
    		update_want_peers();
    	}

    #ifndef TORRENT_NO_DEPRECATE
    	void torrent::refresh_explicit_cache(int cache_size)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		if (!ready_for_connections()) return;

    		if (m_abort) return;
    		TORRENT_ASSERT(m_storage);

    		if (!is_loaded()) return;

    		// rotate the cached pieces
    		cache_status status;
    		m_ses.disk_thread().get_cache_info(&status, false, m_storage.get());

    		// add blocks_per_piece / 2 in order to round to closest whole piece
    		int blocks_per_piece = m_torrent_file->piece_length() / block_size();
    		int num_cache_pieces = (cache_size + blocks_per_piece / 2) / blocks_per_piece;
    		if (num_cache_pieces > m_torrent_file->num_pieces())
    			num_cache_pieces = m_torrent_file->num_pieces();

    		std::vector<int> avail_vec;
    		if (has_picker())
    		{
    			m_picker->get_availability(avail_vec);
    		}
    		else
    		{
    			// we don't keep track of availability, do it the expensive way
    			// do a linear search from the first piece
    			for (int i = 0; i < m_torrent_file->num_pieces(); ++i)
    			{

relevance 2 | ../src/tracker_manager.cpp:203 | some of these arguments could probably be moved to the tracker request itself. like the ip_filter and settings

## some of these arguments could probably be moved to the tracker request itself. like the ip_filter and settings

#### ../src/tracker_manager.cpp:203

    			, interval == 0 ? min_interval : interval);
    		close();
    	}

    	void tracker_connection::sent_bytes(int bytes)
    	{
    		m_man.sent_bytes(bytes);
    	}

    	void tracker_connection::received_bytes(int bytes)
    	{
    		m_man.received_bytes(bytes);
    	}

    	void tracker_connection::close()
    	{
    		cancel();
    		m_man.remove_request(this);
    	}

    	tracker_manager::tracker_manager(class udp_socket& sock
    		, counters& stats_counters
    		, resolver_interface& resolver
    		, aux::session_settings const& sett
    #if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
    		, aux::session_logger& ses
    #endif
    		)
    		: m_udp_socket(sock)
    		, m_host_resolver(resolver)
    		, m_settings(sett)
    		, m_stats_counters(stats_counters)
    #if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
    		, m_ses(ses)
    #endif
    		, m_abort(false)
    	{}

    	tracker_manager::~tracker_manager()
    	{
    		TORRENT_ASSERT(m_abort);
    		abort_all_requests(true);
    	}

    	void tracker_manager::sent_bytes(int bytes)
    	{
    		TORRENT_ASSERT(m_ses.is_single_thread());
    		m_stats_counters.inc_stats_counter(counters::sent_tracker_bytes, bytes);
    	}

    	void tracker_manager::received_bytes(int bytes)

relevance 2 | ../src/udp_socket.cpp:816 | the udp_socket should really just be a single socket, and the session should support having more than one, just like with TCP sockets for now, just make bind failures non-fatal

## the udp_socket should really just be a single socket, and the session should support having more than one, just like with TCP sockets for now, just make bind failures non-fatal

#### ../src/udp_socket.cpp:816

    		m_ipv4_sock.open(udp::v4(), ec);
    		if (ec) return;

    		// this is best-effort. ignore errors
    		error_code err;
    #ifdef TORRENT_WINDOWS
    		m_ipv4_sock.set_option(exclusive_address_use(true), err);
    #else
    		m_ipv4_sock.set_option(boost::asio::socket_base::reuse_address(true), err);
    #endif

    		m_ipv4_sock.bind(ep, ec);
    		if (ec) return;
    		udp::socket::non_blocking_io ioc(true);
    		m_ipv4_sock.io_control(ioc, ec);
    		if (ec) return;
    		setup_read(&m_ipv4_sock);
    	}

    #if TORRENT_USE_IPV6
    	if (supports_ipv6() && (ep.address().is_v6() || is_any(ep.address())))
    	{
    		udp::endpoint ep6 = ep;
    		if (is_any(ep.address())) ep6.address(address_v6::any());
    		m_ipv6_sock.open(udp::v6(), ec);
    		if (ec) return;

    		// this is best-effort. ignore errors
    		error_code err;
    #ifdef TORRENT_WINDOWS
    		m_ipv6_sock.set_option(exclusive_address_use(true), err);
    #else
    		m_ipv6_sock.set_option(boost::asio::socket_base::reuse_address(true), err);
    #endif
    		m_ipv6_sock.set_option(boost::asio::ip::v6_only(true), err);

    		m_ipv6_sock.bind(ep6, ec);
    		if (ec != error_code(boost::system::errc::address_not_available
    			, boost::system::generic_category()))
    		{
    			if (ec) return;
    			udp::socket::non_blocking_io ioc(true);
    			m_ipv6_sock.io_control(ioc, ec);
    			if (ec) return;
    			setup_read(&m_ipv6_sock);
    		}
    		else
    		{
    			ec.clear();
    		}
    	}

relevance 2 | ../src/udp_tracker_connection.cpp:83 | support authentication here. tracker_req().auth

## support authentication here. tracker_req().auth

#### ../src/udp_tracker_connection.cpp:83

    		udp_tracker_connection::m_connection_cache;

    	mutex udp_tracker_connection::m_cache_mutex;

    	udp_tracker_connection::udp_tracker_connection(
    		io_service& ios
    		, tracker_manager& man
    		, tracker_request const& req
    		, boost::weak_ptr<request_callback> c)
    		: tracker_connection(man, req, ios, c)
    		, m_transaction_id(0)
    		, m_attempts(0)
    		, m_state(action_error)
    		, m_abort(false)
    	{
    		update_transaction_id();
    	}

    	void udp_tracker_connection::start()
    	{
    		std::string hostname;
    		std::string protocol;
    		int port;
    		error_code ec;

    		using boost::tuples::ignore;
    		boost::tie(protocol, ignore, hostname, port, ignore)
    			= parse_url_components(tracker_req().url, ec);
    		if (port == -1) port = protocol == "http" ? 80 : 443;

    		if (ec)
    		{
    			tracker_connection::fail(ec);
    			return;
    		}

    		aux::session_settings const& settings = m_man.settings();

    		if (settings.get_bool(settings_pack::proxy_hostnames)
    			&& (settings.get_int(settings_pack::proxy_type) == settings_pack::socks5
    				|| settings.get_int(settings_pack::proxy_type) == settings_pack::socks5_pw))
    		{
    			m_hostname = hostname;
    			m_target.port(port);
    			start_announce();
    		}
    		else
    		{
    #if defined TORRENT_ASIO_DEBUGGING
    			add_outstanding_async("udp_tracker_connection::name_lookup");
    #endif

relevance 2 | ../src/ut_metadata.cpp:123 | if we were to initialize m_metadata_size lazily instead, we would probably be more efficient initialize m_metadata_size

## if we were to initialize m_metadata_size lazily instead, we would probably be more efficient initialize m_metadata_size

#### ../src/ut_metadata.cpp:123

    				metadata();
    		}

    		bool need_loaded()
    		{ return m_torrent.need_loaded(); }

    		virtual void on_unload() TORRENT_OVERRIDE
    		{
    			m_metadata.reset();
    		}

    		virtual void on_load() TORRENT_OVERRIDE
    		{
    			// initialize m_metadata_size
    			TORRENT_ASSERT(m_torrent.is_loaded());
    			metadata();
    		}

    		virtual void on_files_checked() TORRENT_OVERRIDE
    		{
    			metadata();
    		}

    		virtual boost::shared_ptr<peer_plugin> new_connection(
    			peer_connection_handle const& pc) TORRENT_OVERRIDE;

    		int get_metadata_size() const
    		{
    			TORRENT_ASSERT(m_metadata_size > 0);
    			return m_metadata_size;
    		}

    		buffer::const_interval metadata() const
    		{
    			if (!m_torrent.need_loaded()) return buffer::const_interval(NULL, NULL);
    			TORRENT_ASSERT(m_torrent.valid_metadata());
    			if (!m_metadata)
    			{
    				m_metadata = m_torrent.torrent_file().metadata();
    				m_metadata_size = m_torrent.torrent_file().metadata_size();
    				TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
    					== m_torrent.torrent_file().info_hash());
    			}
    			return buffer::const_interval(m_metadata.get(), m_metadata.get()
    				+ m_metadata_size);
    		}

    		bool received_metadata(ut_metadata_peer_plugin& source
    			, char const* buf, int size, int piece, int total_size);

    		// returns a piece of the metadata that

relevance 2 | ../src/utp_socket_manager.cpp:244 | we may want to take ec into account here. possibly close connections quicker

## we may want to take ec into account here. possibly close connections quicker

#### ../src/utp_socket_manager.cpp:244

    			error_code err;
    			m_interfaces = enum_net_interfaces(m_sock.get_io_service(), err);
    			if (err) return socket_ep;
    		}

    		for (std::vector<ip_interface>::iterator i = m_interfaces.begin()
    			, end(m_interfaces.end()); i != end; ++i)
    		{
    			if (i->interface_address.is_v4() != remote.is_v4())
    				continue;

    			if (strcmp(best->name, i->name) == 0)
    				return tcp::endpoint(i->interface_address, socket_ep.port());
    		}
    		return socket_ep;
    	}

    	bool utp_socket_manager::incoming_packet(error_code const& ec, udp::endpoint const& ep
    			, char const* p, int size)
    	{
    		TORRENT_UNUSED(ec);
    //		UTP_LOGV("incoming packet size:%d\n", size);

    		if (size < int(sizeof(utp_header))) return false;

    		utp_header const* ph = reinterpret_cast<utp_header const*>(p);

    //		UTP_LOGV("incoming packet version:%d\n", int(ph->get_version()));

    		if (ph->get_version() != 1) return false;

    		const time_point receive_time = clock_type::now();

    		// parse out connection ID and look for existing
    		// connections. If found, forward to the utp_stream.
    		boost::uint16_t id = ph->connection_id;

    		// first test to see if it's the same socket as last time
    		// in most cases it is
    		if (m_last_socket
    			&& utp_match(m_last_socket, ep, id))
    		{
    			return utp_incoming_packet(m_last_socket, p, size, ep, receive_time);
    		}

    		std::pair<socket_map_t::iterator, socket_map_t::iterator> r =
    			m_utp_sockets.equal_range(id);

    		for (; r.first != r.second; ++r.first)
    		{
    			if (!utp_match(r.first->second, ep, id)) continue;

relevance 2 | ../src/utp_stream.cpp:386 | it would be nice if not everything would have to be public here

## it would be nice if not everything would have to be public here

#### ../src/utp_stream.cpp:386

    	void incoming(boost::uint8_t const* buf, int size, packet* p, time_point now);
    	void do_ledbat(int acked_bytes, int delay, int in_flight);
    	int packet_timeout() const;
    	bool test_socket_state();
    	void maybe_trigger_receive_callback();
    	void maybe_trigger_send_callback();
    	bool cancel_handlers(error_code const& ec, bool kill);
    	bool consume_incoming_data(
    		utp_header const* ph, boost::uint8_t const* ptr, int payload_size, time_point now);
    	void update_mtu_limits();
    	void experienced_loss(int seq_nr);

    	void set_state(int s);

    private:

    	// non-copyable
    	utp_socket_impl(utp_socket_impl const&);
    	utp_socket_impl const& operator=(utp_socket_impl const&);

    public:

    	void check_receive_buffers() const;

    #if TORRENT_USE_INVARIANT_CHECKS
    	void check_invariant() const;
    #endif

    	utp_socket_manager* m_sm;

    	// userdata pointer passed along
    	// with any callback. This is initialized to 0
    	// then set to point to the utp_stream when
    	// hooked up, and then reset to 0 once the utp_stream
    	// detaches. This is used to know whether or not
    	// the socket impl is still attached to a utp_stream
    	// object. When it isn't, we'll never be able to
    	// signal anything back to the client, and in case
    	// of errors, we just have to delete ourselves
    	// i.e. transition to the UTP_STATE_DELETED state
    	void* m_userdata;

    	// This is a platform-independent replacement
    	// for the regular iovec type in posix. Since
    	// it's not used in any system call, we might as
    	// well define our own type instead of wrapping
    	// the system's type.
    	struct iovec_t
    	{
    		iovec_t(void* b, size_t l): buf(b), len(l) {}
    		void* buf;

relevance 2 | ../src/web_peer_connection.cpp:329 | do we really need a special case here? wouldn't the multi-file case handle single file torrents correctly too?

## do we really need a special case here? wouldn't the multi-file case handle single file torrents correctly too?

#### ../src/web_peer_connection.cpp:329

    			m_web->restart_request.piece = -1;
    		}

    #if 0
    			std::cerr << this << " REQ: p: " << pr.piece << " " << pr.start << std::endl;
    #endif
    		size -= pr.length;
    	}

    	bool const single_file_request = t->torrent_file().num_files() == 1;
    	int const proxy_type = m_settings.get_int(settings_pack::proxy_type);
    	bool const using_proxy = (proxy_type == settings_pack::http
    		|| proxy_type == settings_pack::http_pw) && !m_ssl;

    	// the number of pad files that have been "requested". In case we _only_
    	// request padfiles, we can't rely on handling them in the on_receive()
    	// callback (because we won't receive anything), instead we have to post a
    	// pretend read callback where we can deliver the zeroes for the partfile
    	int num_pad_files = 0;

    	if (single_file_request)
    	{
    		file_request_t file_req;
    		file_req.file_index = 0;
    		file_req.start = boost::int64_t(req.piece) * info.piece_length()
    			+ req.start;
    		file_req.length = req.length;

    		request += "GET ";
    		// do not encode single file paths, they are
    		// assumed to be encoded in the torrent file
    		request += using_proxy ? m_url : m_path;
    		request += " HTTP/1.1\r\n";
    		add_headers(request, m_settings, using_proxy);
    		request += "\r\nRange: bytes=";
    		request += to_string(file_req.start).elems;
    		request += "-";
    		request += to_string(file_req.start + file_req.length - 1).elems;
    		request += "\r\n\r\n";
    		m_first_request = false;

    		m_file_requests.push_back(file_req);
    	}
    	else
    	{
    		if (!t->need_loaded())
    		{
    			disconnect(errors::torrent_aborted, op_bittorrent);
    			return;
    		}

relevance 2 | ../src/web_peer_connection.cpp:551 | just make this peer not have the pieces associated with the file we just requested. Only when it doesn't have any of the file do the following

## just make this peer not have the pieces associated with the file we just requested. Only when it doesn't have any of the file do the following

#### ../src/web_peer_connection.cpp:551

    	peer_connection::received_invalid_data(index, single_peer);

    	// if we don't think we have any of the files, allow banning the web seed
    	if (num_have_pieces() == 0) return true;

    	// don't disconnect, we won't request anything from this file again
    	return false;
    }

    void web_peer_connection::on_receive_padfile()
    {
    	handle_padfile();
    }

    void web_peer_connection::handle_error(int bytes_left)
    {
    	boost::shared_ptr<torrent> t = associated_torrent().lock();
    	TORRENT_ASSERT(t);

    	int retry_time = atoi(m_parser.header("retry-after").c_str());
    	if (retry_time <= 0) retry_time = m_settings.get_int(settings_pack::urlseed_wait_retry);
    	// temporarily unavailable, retry later
    	t->retry_web_seed(this, retry_time);
    	std::string error_msg = to_string(m_parser.status_code()).elems
    		+ (" " + m_parser.message());
    	if (t->alerts().should_post<url_seed_alert>())
    	{
    		t->alerts().emplace_alert<url_seed_alert>(t->get_handle(), m_url
    			, error_msg);
    	}
    	received_bytes(0, bytes_left);
    	disconnect(error_code(m_parser.status_code(), http_category()), op_bittorrent, 1);
    	return;
    }

    void web_peer_connection::handle_redirect(int bytes_left)
    {
    	// this means we got a redirection request
    	// look for the location header
    	std::string location = m_parser.header("location");
    	received_bytes(0, bytes_left);

    	boost::shared_ptr<torrent> t = associated_torrent().lock();
    	TORRENT_ASSERT(t);

    	if (location.empty())
    	{
    		// we should not try this server again.
    		t->remove_web_seed(this, errors::missing_location, op_bittorrent, 2);
    		m_web = NULL;

relevance 2 | ../src/web_peer_connection.cpp:603 | create a mapping of file-index to redirection URLs. Use that to form URLs instead. Support to reconnect to a new server without destructing this peer_connection

## create a mapping of file-index to redirection URLs. Use that to form URLs instead. Support to reconnect to a new server without destructing this peer_connection

#### ../src/web_peer_connection.cpp:603

    		t->remove_web_seed(this, errors::missing_location, op_bittorrent, 2);
    		m_web = NULL;
    		TORRENT_ASSERT(is_disconnecting());
    		return;
    	}

    	bool const single_file_request = !m_path.empty()
    		&& m_path[m_path.size() - 1] != '/';

    	// add the redirected url and remove the current one
    	if (!single_file_request)
    	{
    		TORRENT_ASSERT(!m_file_requests.empty());
    		int const file_index = m_file_requests.front().file_index;

    		if (!t->need_loaded())
    		{
    			disconnect(errors::torrent_aborted, op_bittorrent);
    			return;
    		}
    		torrent_info const& info = t->torrent_file();
    		std::string path = info.orig_files().file_path(file_index);
    #ifdef TORRENT_WINDOWS
    		convert_path_to_posix(path);
    #endif
    		path = escape_path(path.c_str(), path.length());
    		size_t i = location.rfind(path);
    		if (i == std::string::npos)
    		{
    			t->remove_web_seed(this, errors::invalid_redirection, op_bittorrent, 2);
    			m_web = NULL;
    			TORRENT_ASSERT(is_disconnecting());
    			return;
    		}
    		location.resize(i);
    	}
    	else
    	{
    		location = resolve_redirect_location(m_url, location);
    	}

    #ifndef TORRENT_DISABLE_LOGGING
    	peer_log(peer_log_alert::info, "LOCATION", "%s", location.c_str());
    #endif
    	t->add_web_seed(location, web_seed_entry::url_seed, m_external_auth, m_extra_headers);
    	t->remove_web_seed(this, errors::redirecting, op_bittorrent, 2);
    	m_web = NULL;
    	TORRENT_ASSERT(is_disconnecting());
    	return;
    }

relevance 2 | ../src/kademlia/dht_storage.cpp:110 | make this configurable in dht_settings

## make this configurable in dht_settings

#### ../src/kademlia/dht_storage.cpp:110

    	// this is a group. It contains a set of group members
    	struct torrent_entry
    	{
    		std::string name;
    		std::set<peer_entry> peers;
    	};

    #ifndef TORRENT_NO_DEPRECATE
    	struct count_peers
    	{
    		int* count;
    		count_peers(int* c): count(c) {}
    		void operator()(std::pair<libtorrent::sha1_hash
    			, torrent_entry> const& t)
    		{
    			*count += t.second.peers.size();
    		}
    	};
    #endif

    	enum { announce_interval = 30 };

    	struct dht_immutable_item
    	{
    		dht_immutable_item() : value(0), num_announcers(0), size(0) {}
    		// malloced space for the actual value
    		char* value;
    		// this counts the number of IPs we have seen
    		// announcing this item, this is used to determine
    		// popularity if we reach the limit of items to store
    		bloom_filter<128> ips;
    		// the last time we heard about this
    		time_point last_seen;
    		// number of IPs in the bloom filter
    		int num_announcers;
    		// size of malloced space pointed to by value
    		int size;
    	};

    	struct ed25519_public_key { char bytes[item_pk_len]; };

    	struct dht_mutable_item : dht_immutable_item
    	{
    		char sig[item_sig_len];
    		boost::int64_t seq;
    		ed25519_public_key key;
    		char* salt;
    		int salt_size;
    	};

    	void touch_item(dht_immutable_item* f, address const& address)

relevance 2 | ../src/kademlia/node.cpp:655 | it would be nice to have a bias towards node-id prefixes that are missing in the bucket

## it would be nice to have a bias towards node-id prefixes that are missing in the bucket

#### ../src/kademlia/node.cpp:655

    	// this shouldn't happen
    	TORRENT_ASSERT(m_id != ne->id);
    	if (ne->id == m_id) return;

    	int bucket = 159 - distance_exp(m_id, ne->id);
    	TORRENT_ASSERT(bucket < 160);
    	send_single_refresh(ne->ep(), bucket, ne->id);
    }

    void node::send_single_refresh(udp::endpoint const& ep, int bucket
    	, node_id const& id)
    {
    	TORRENT_ASSERT(id != m_id);
    	void* ptr = m_rpc.allocate_observer();
    	if (ptr == 0) return;

    	TORRENT_ASSERT(bucket >= 0);
    	TORRENT_ASSERT(bucket <= 159);

    	// generate a random node_id within the given bucket
    	node_id mask = generate_prefix_mask(bucket + 1);
    	node_id target = generate_secret_id() & ~mask;
    	target |= m_id & mask;

    	// create a dummy traversal_algorithm
    	// this is unfortunately necessary for the observer
    	// to free itself from the pool when it's being released
    	boost::intrusive_ptr<traversal_algorithm> algo(
    		new traversal_algorithm(*this, (node_id::min)()));
    	observer_ptr o(new (ptr) ping_observer(algo, ep, id));
    #if defined TORRENT_DEBUG || defined TORRENT_RELEASE_ASSERTS
    	o->m_in_constructor = false;
    #endif
    	entry e;
    	e["y"] = "q";
    	entry& a = e["a"];

    	if (m_table.is_full(bucket))
    	{
    		// current bucket is full, just ping it.
    		e["q"] = "ping";
    		m_counters.inc_stats_counter(counters::dht_ping_out);
    	}
    	else
    	{
    		// use get_peers instead of find_node. We'll get nodes in the response
    		// either way.
    		e["q"] = "get_peers";
    		a["info_hash"] = target.to_string();
    		m_counters.inc_stats_counter(counters::dht_get_peers_out);
    	}

relevance 2 | ../src/kademlia/node.cpp:739 | use the non deprecated function instead of this one

## use the non deprecated function instead of this one

#### ../src/kademlia/node.cpp:739

    		(*i)->status(lookup);
    	}
    }

    void node::update_stats_counters(counters& c) const
    {
    	const dht_storage_counters& dht_cnt = m_storage->counters();
    	c.set_value(counters::dht_torrents, dht_cnt.torrents);
    	c.set_value(counters::dht_peers, dht_cnt.peers);
    	c.set_value(counters::dht_immutable_data, dht_cnt.immutable_data);
    	c.set_value(counters::dht_mutable_data, dht_cnt.mutable_data);

    	int nodes, replacements;
    	boost::tie(nodes, replacements, boost::tuples::ignore) = size();
    	c.set_value(counters::dht_nodes, nodes);
    	c.set_value(counters::dht_node_cache, replacements);
    	c.set_value(counters::dht_allocated_observers, m_rpc.num_allocated_observers());
    }

    #ifndef TORRENT_NO_DEPRECATE
    void node::status(session_status& s)
    {
    	mutex_t::scoped_lock l(m_mutex);

    	m_table.status(s);
    	s.dht_torrents = int(m_storage->num_torrents());
    	s.active_requests.clear();
    	s.dht_total_allocations = m_rpc.num_allocated_observers();
    	for (std::set<traversal_algorithm*>::iterator i = m_running_requests.begin()
    		, end(m_running_requests.end()); i != end; ++i)
    	{
    		s.active_requests.push_back(dht_lookup());
    		dht_lookup& lookup = s.active_requests.back();
    		(*i)->status(lookup);
    	}
    }
    #endif

    void node::lookup_peers(sha1_hash const& info_hash, entry& reply
    	, bool noseed, bool scrape) const
    {
    	if (m_observer)
    		m_observer->get_peers(info_hash);

    	m_storage->get_peers(info_hash, noseed, scrape, reply);
    }

    void TORRENT_EXTRA_EXPORT write_nodes_entry(entry& r, nodes_t const& nodes)
    {
    	entry& n = r["nodes"];
    	std::back_insert_iterator<std::string> out(n.string());

relevance 2 | ../src/kademlia/node.cpp:898 | find_node should write directly to the response entry

## find_node should write directly to the response entry

#### ../src/kademlia/node.cpp:898

    				, int(reply["values"].list().size()));
    		}
    #endif
    	}
    	else if (query_len == 9 && memcmp(query, "find_node", 9) == 0)
    	{
    		key_desc_t msg_desc[] = {
    			{"target", bdecode_node::string_t, 20, 0},
    		};

    		bdecode_node msg_keys[1];
    		if (!verify_message(arg_ent, msg_desc, msg_keys, error_string, sizeof(error_string)))
    		{
    			incoming_error(e, error_string);
    			return;
    		}

    		m_counters.inc_stats_counter(counters::dht_find_node_in);
    		sha1_hash target(msg_keys[0].string_ptr());

    		nodes_t n;
    		m_table.find_node(target, n, 0);
    		write_nodes_entry(reply, n);
    	}
    	else if (query_len == 13 && memcmp(query, "announce_peer", 13) == 0)
    	{
    		key_desc_t msg_desc[] = {
    			{"info_hash", bdecode_node::string_t, 20, 0},
    			{"port", bdecode_node::int_t, 0, 0},
    			{"token", bdecode_node::string_t, 0, 0},
    			{"n", bdecode_node::string_t, 0, key_desc_t::optional},
    			{"seed", bdecode_node::int_t, 0, key_desc_t::optional},
    			{"implied_port", bdecode_node::int_t, 0, key_desc_t::optional},
    		};

    		bdecode_node msg_keys[6];
    		if (!verify_message(arg_ent, msg_desc, msg_keys, error_string, sizeof(error_string)))
    		{
    			m_counters.inc_stats_counter(counters::dht_invalid_announce);
    			incoming_error(e, error_string);
    			return;
    		}

    		int port = int(msg_keys[1].int_value());

    		// is the announcer asking to ignore the explicit
    		// listen port and instead use the source port of the packet?
    		if (msg_keys[5] && msg_keys[5].int_value() != 0)
    			port = m.addr.port();

    		if (port < 0 || port >= 65536)

relevance 2 | ../src/kademlia/routing_table.cpp:132 | use the non deprecated function instead of this one

## use the non deprecated function instead of this one

#### ../src/kademlia/routing_table.cpp:132

    	static const int size_exceptions[] = {16, 8, 4, 2};
    	if (bucket < int(sizeof(size_exceptions)/sizeof(size_exceptions[0])))
    		return m_bucket_size * size_exceptions[bucket];
    	return m_bucket_size;
    }

    void routing_table::status(std::vector<dht_routing_bucket>& s) const
    {
    	for (table_t::const_iterator i = m_buckets.begin()
    		, end(m_buckets.end()); i != end; ++i)
    	{
    		dht_routing_bucket b;
    		b.num_nodes = i->live_nodes.size();
    		b.num_replacements = i->replacements.size();
    		s.push_back(b);
    	}
    }

    #ifndef TORRENT_NO_DEPRECATE
    void routing_table::status(session_status& s) const
    {
    	int ignore;
    	boost::tie(s.dht_nodes, s.dht_node_cache, ignore) = size();
    	s.dht_global_nodes = num_global_nodes();

    	for (table_t::const_iterator i = m_buckets.begin()
    		, end(m_buckets.end()); i != end; ++i)
    	{
    		dht_routing_bucket b;
    		b.num_nodes = i->live_nodes.size();
    		b.num_replacements = i->replacements.size();
    #ifndef TORRENT_NO_DEPRECATE
    		b.last_active = 0;
    #endif
    		s.dht_routing_table.push_back(b);
    	}
    }
    #endif

    boost::tuple<int, int, int> routing_table::size() const
    {
    	int nodes = 0;
    	int replacements = 0;
    	int confirmed = 0;
    	for (table_t::const_iterator i = m_buckets.begin()
    		, end(m_buckets.end()); i != end; ++i)
    	{
    		nodes += i->live_nodes.size();
    		for (bucket_t::const_iterator k = i->live_nodes.begin()
    			, end2(i->live_nodes.end()); k != end2; ++k)

relevance 2 | ../src/kademlia/routing_table.cpp:982 | move the lowest priority nodes to the replacement bucket

## move the lowest priority nodes to the replacement bucket

#### ../src/kademlia/routing_table.cpp:982

    	bucket_t& rb = m_buckets[bucket_index].replacements;

    	// move any node whose (160 - distane_exp(m_id, id)) >= (i - m_buckets.begin())
    	// to the new bucket
    	int const new_bucket_size = bucket_limit(bucket_index + 1);
    	for (bucket_t::iterator j = b.begin(); j != b.end();)
    	{
    		int const d = distance_exp(m_id, j->id);
    		if (d >= 159 - bucket_index)
    		{
    			++j;
    			continue;
    		}
    		// this entry belongs in the new bucket
    		new_bucket.push_back(*j);
    		j = b.erase(j);
    	}

    	if (b.size() > bucket_size_limit)
    	{
    		for (bucket_t::iterator i = b.begin() + bucket_size_limit
    			, end(b.end()); i != end; ++i)
    		{
    			rb.push_back(*i);
    		}

    		b.resize(bucket_size_limit);
    	}

    	// split the replacement bucket as well. If the live bucket
    	// is not full anymore, also move the replacement entries
    	// into the main bucket
    	for (bucket_t::iterator j = rb.begin(); j != rb.end();)
    	{
    		if (distance_exp(m_id, j->id) >= 159 - bucket_index)
    		{
    			if (int(b.size()) >= bucket_size_limit)
    			{
    				++j;
    				continue;
    			}
    			b.push_back(*j);
    		}
    		else
    		{
    			// this entry belongs in the new bucket
    			if (int(new_bucket.size()) < new_bucket_size)
    				new_bucket.push_back(*j);
    			else
    				new_replacement_bucket.push_back(*j);
    		}

relevance 2 | ../include/libtorrent/alert_types.hpp:1448 | should the alert base class have this object instead?

## should the alert base class have this object instead?

#### ../include/libtorrent/alert_types.hpp:1448

    	{
    		// internal
    		portmap_log_alert(aux::stack_allocator& alloc, int t, const char* m);

    		TORRENT_DEFINE_ALERT(portmap_log_alert, 52)

    		static const int static_category = alert::port_mapping_log_notification;
    		virtual std::string message() const TORRENT_OVERRIDE;

    		int map_type;

    #ifndef TORRENT_NO_DEPRECATE
    		std::string TORRENT_DEPRECATED_MEMBER msg;
    #endif

    		// the message associated with this log line
    		char const* log_message() const;

    	private:

    		aux::stack_allocator const& m_alloc;

    		int m_log_idx;
    	};

    #endif

    	// This alert is generated when a fastresume file has been passed to
    	// add_torrent() but the files on disk did not match the fastresume file.
    	// The error_code explains the reason why the resume file was rejected.
    	struct TORRENT_EXPORT fastresume_rejected_alert TORRENT_FINAL : torrent_alert
    	{
    		// internal
    		fastresume_rejected_alert(aux::stack_allocator& alloc
    			, torrent_handle const& h
    			, error_code const& ec
    			, std::string const& file
    			, char const* op);

    		TORRENT_DEFINE_ALERT(fastresume_rejected_alert, 53)

    		static const int static_category = alert::status_notification
    			| alert::error_notification;
    		virtual std::string message() const TORRENT_OVERRIDE;

    		error_code error;

    #ifndef TORRENT_NO_DEPRECATE
    		// If the error happened to a specific file, ``file`` is the path to it.
    		std::string TORRENT_DEPRECATED_MEMBER file;
    #endif

relevance 2 | ../include/libtorrent/broadcast_socket.hpp:53 | facto these functions out

## facto these functions out

#### ../include/libtorrent/broadcast_socket.hpp:53

    #ifndef TORRENT_BROADCAST_SOCKET_HPP_INCLUDED
    #define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED

    #include "libtorrent/config.hpp"
    #include "libtorrent/io_service_fwd.hpp"
    #include "libtorrent/socket.hpp"
    #include "libtorrent/address.hpp"
    #include "libtorrent/error_code.hpp"

    #include "libtorrent/aux_/disable_warnings_push.hpp"

    #include <boost/shared_ptr.hpp>
    #include <boost/function/function3.hpp>
    #include <list>

    #include "libtorrent/aux_/disable_warnings_pop.hpp"

    namespace libtorrent
    {

    	TORRENT_EXTRA_EXPORT bool is_local(address const& a);
    	TORRENT_EXTRA_EXPORT bool is_loopback(address const& addr);
    	TORRENT_EXTRA_EXPORT bool is_multicast(address const& addr);
    	TORRENT_EXTRA_EXPORT bool is_any(address const& addr);
    	TORRENT_EXTRA_EXPORT bool is_teredo(address const& addr);
    	TORRENT_EXTRA_EXPORT int cidr_distance(address const& a1, address const& a2);
    	bool is_ip_address(char const* host);

    	// determines if the operating system supports IPv6
    	TORRENT_EXTRA_EXPORT bool supports_ipv6();

    	TORRENT_EXTRA_EXPORT int common_bits(unsigned char const* b1
    		, unsigned char const* b2, int n);

    	typedef boost::function<void(udp::endpoint const& from
    		, char* buffer, int size)> receive_handler_t;

    	class TORRENT_EXTRA_EXPORT broadcast_socket
    	{
    	public:
    		broadcast_socket(udp::endpoint const& multicast_endpoint);
    		~broadcast_socket() { close(); }

    		void open(receive_handler_t const& handler, io_service& ios
    			, error_code& ec, bool loopback = true);

    		enum flags_t { broadcast = 1 };
    		void send(char const* buffer, int size, error_code& ec, int flags = 0);

    		void close();
    		int num_send_sockets() const { return int(m_unicast_sockets.size()); }

relevance 2 | ../include/libtorrent/build_config.hpp:40 | instead of using a dummy function to cause link errors when incompatible build configurations are used, make the namespace name depend on the configuration, and have a using declaration in the headers to pull it into libtorrent.

## instead of using a dummy function to cause link errors when incompatible build configurations are used, make the namespace name depend on the configuration, and have a using declaration in the headers to pull it into libtorrent.

#### ../include/libtorrent/build_config.hpp:40

    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    */

    #ifndef TORRENT_BUILD_CONFIG_HPP_INCLUDED
    #define TORRENT_BUILD_CONFIG_HPP_INCLUDED

    #include "libtorrent/config.hpp"
    #include <boost/preprocessor/cat.hpp>
    #include <boost/preprocessor/stringize.hpp>

    #if TORRENT_USE_IPV6
    #define TORRENT_CFG_IPV6 ipv6_
    #else
    #define TORRENT_CFG_IPV6 noipv6_
    #endif

    #ifdef TORRENT_NO_DEPRECATE
    #define TORRENT_CFG_DEPR nodeprecate_
    #else
    #define TORRENT_CFG_DEPR deprecated_
    #endif

    #define TORRENT_CFG \
    	BOOST_PP_CAT(TORRENT_CFG_IPV6, \
    	TORRENT_CFG_DEPR)

    #define TORRENT_CFG_STRING BOOST_PP_STRINGIZE(TORRENT_CFG)

    #endif

relevance 2 | ../include/libtorrent/enum_net.hpp:151 | this could be done more efficiently by just looking up the interface with the given name, maybe even with if_nametoindex()

## this could be done more efficiently by just looking up the interface with the given name, maybe even with if_nametoindex()

#### ../include/libtorrent/enum_net.hpp:151

    			// providing 0.0.0.0 as the device, turn it into "::"
    			if (ip == address_v4::any() && protocol == boost::asio::ip::tcp::v6())
    				ip = address_v6::any();
    #endif
    			bind_ep.address(ip);
    			// it appears to be an IP. Just bind to that address
    			sock.bind(bind_ep, ec);
    			return bind_ep.address();
    		}

    		ec.clear();

    #ifdef SO_BINDTODEVICE
    		// try to use SO_BINDTODEVICE here, if that exists. If it fails,
    		// fall back to the mechanism we have below
    		sock.set_option(bind_to_device_opt(device_name), ec);
    		if (ec)
    #endif
    		{
    			ec.clear();
    			std::vector<ip_interface> ifs = enum_net_interfaces(ios, ec);
    			if (ec) return bind_ep.address();

    			bool found = false;

    			for (int i = 0; i < int(ifs.size()); ++i)
    			{
    				// we're looking for a specific interface, and its address
    				// (which must be of the same family as the address we're
    				// connecting to)
    				if (strcmp(ifs[i].name, device_name) != 0) continue;
    				if (ifs[i].interface_address.is_v4() != (protocol == boost::asio::ip::tcp::v4()))
    					continue;

    				bind_ep.address(ifs[i].interface_address);
    				found = true;
    				break;
    			}

    			if (!found)
    			{
    				ec = error_code(boost::system::errc::no_such_device, generic_category());
    				return bind_ep.address();
    			}
    		}
    		sock.bind(bind_ep, ec);
    		return bind_ep.address();
    	}

    	// returns the device name whose local address is ``addr``. If
    	// no such device is found, an empty string is returned.

relevance 2 | ../include/libtorrent/heterogeneous_queue.hpp:56 | add emplace_back() version

## add emplace_back() version

#### ../include/libtorrent/heterogeneous_queue.hpp:56

    #include <vector>

    #include <boost/cstdint.hpp>
    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits/is_base_of.hpp>

    #include "libtorrent/assert.hpp"

    namespace libtorrent {

    	template <class T>
    	struct heterogeneous_queue
    	{
    		heterogeneous_queue()
    			: m_storage(NULL)
    			, m_capacity(0)
    			, m_size(0)
    			, m_num_items(0)
    		{}

    		template <class U>
    		typename boost::enable_if<boost::is_base_of<T, U> >::type
    		push_back(U const& a)
    		{
    			// the size of the type rounded up to pointer alignment
    			const int object_size = (sizeof(U) + sizeof(*m_storage) - 1)
    				/ sizeof(*m_storage);

    			// +1 for the length prefix
    			if (m_size + object_size + header_size > m_capacity)
    				grow_capacity(object_size);

    			uintptr_t* ptr = m_storage + m_size;

    			// length prefix
    			header_t* hdr = reinterpret_cast<header_t*>(ptr);
    			hdr->len = object_size;
    			hdr->move = &move<U>;
    			ptr += header_size;

    			// construct in-place
    			new (ptr) U(a);

    			// if we constructed the object without throwing any exception
    			// update counters to indicate the new item is in there
    			++m_num_items;
    			m_size += header_size + object_size;
    		}

    		void get_pointers(std::vector<T*>& out)
    		{

relevance 2 | ../include/libtorrent/peer_connection.hpp:1118 | rename this target queue size

## rename this target queue size

#### ../include/libtorrent/peer_connection.hpp:1118

    		// the number of bytes send to the disk-io
    		// thread that hasn't yet been completely written.
    		int m_outstanding_writing_bytes;

    		// max transfer rates seen on this peer
    		int m_download_rate_peak;
    		int m_upload_rate_peak;

    		// when using the BitTyrant choker, this is our
    		// estimated reciprocation rate. i.e. the rate
    		// we need to send to this peer for it to unchoke
    		// us
    		int m_est_reciprocation_rate;

    		// stop sending data after this many bytes, INT_MAX = inf
    		int m_send_barrier;

    		// the number of request we should queue up
    		// at the remote end.
    		boost::uint16_t m_desired_queue_size;

    #ifndef TORRENT_NO_DEPRECATE
    #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
    		// in case the session settings is set
    		// to resolve countries, this is set to
    		// the two character country code this
    		// peer resides in.
    		char m_country[2];
    #endif
    #endif // TORRENT_NO_DEPRECATE

    		// if set to non-zero, this peer will always prefer
    		// to request entire n pieces, rather than blocks.
    		// where n is the value of this variable.
    		// if it is 0, the download rate limit setting
    		// will be used to determine if whole pieces
    		// are preferred.
    		int m_prefer_contiguous_blocks;

    		// this is the number of times this peer has had
    		// a request rejected because of a disk I/O failure.
    		// once this reaches a certain threshold, the
    		// peer is disconnected in order to avoid infinite
    		// loops of consistent failures
    		boost::uint8_t m_disk_read_failures;

    		// this is used in seed mode whenever we trigger a hash check
    		// for a piece, before we read it. It's used to throttle
    		// the hash checks to just a few per peer at a time.
    		boost::uint8_t m_outstanding_piece_verification:3;

relevance 2 | ../include/libtorrent/piece_picker.hpp:594 | having 8 priority levels is probably excessive. It should probably be changed to 3 levels + dont-download

## having 8 priority levels is probably excessive. It should probably be changed to 3 levels + dont-download

#### ../include/libtorrent/piece_picker.hpp:594

    			// the number of peers that has this piece
    			// (availability)
    #ifdef TORRENT_OPTIMIZE_MEMORY_USAGE
    			boost::uint32_t peer_count : 9;
    #else
    			boost::uint32_t peer_count : 16;
    #endif

    			// one of the enums from state_t. This indicates whether this piece
    			// is currently being downloaded or not, and what state it's in if
    			// it is. Specifically, as an optimization, pieces that have all blocks
    			// requested from them are separated out into separate lists to make
    			// lookups quicker. The main oddity is that whether a downloading piece
    			// has only been requested from peers that are reverse, that's
    			// recorded as piece_downloading_reverse, which really means the same
    			// as piece_downloading, it just saves space to also indicate that it
    			// has a bit lower priority. The reverse bit is only relevant if the
    			// state is piece_downloading.
    			boost::uint32_t download_state : 3;

    			// is 0 if the piece is filtered (not to be downloaded)
    			// 1 is low priority
    			// 2 is low priority
    			// 3 is mid priority
    			// 4 is default priority
    			// 5 is mid priority
    			// 6 is high priority
    			// 7 is high priority
    			boost::uint32_t piece_priority : 3;

    			// index in to the piece_info vector
    #ifdef TORRENT_OPTIMIZE_MEMORY_USAGE
    			boost::uint32_t index : 17;
    #else
    			boost::uint32_t index;
    #endif

    #ifdef TORRENT_DEBUG_REFCOUNTS
    			// all the peers that have this piece
    			std::set<const torrent_peer*> have_peers;
    #endif

    			enum
    			{
    				// index is set to this to indicate that we have the
    				// piece. There is no entry for the piece in the
    				// buckets if this is the case.
    #ifdef TORRENT_OPTIMIZE_MEMORY_USAGE
    				we_have_index = 0x3ffff,
    #else

relevance 2 | ../include/libtorrent/proxy_base.hpp:260 | use the resolver interface that has a built-in cache

## use the resolver interface that has a built-in cache

#### ../include/libtorrent/proxy_base.hpp:260

    		return m_sock.lowest_layer();
    	}

    	next_layer_type& next_layer()
    	{
    		return m_sock;
    	}

    	bool is_open() const { return m_sock.is_open(); }

    protected:

    	bool handle_error(error_code const& e, boost::shared_ptr<handler_type> const& h);

    	tcp::socket m_sock;
    	std::string m_hostname; // proxy host
    	int m_port;             // proxy port

    	endpoint_type m_remote_endpoint;

    	tcp::resolver m_resolver;
    };

    }

    #endif

relevance 2 | ../include/libtorrent/session_handle.hpp:78 | the ip filter should probably be saved here too

## the ip filter should probably be saved here too

#### ../include/libtorrent/session_handle.hpp:78

    	class port_filter;
    	class alert;

    #ifndef TORRENT_NO_DEPRECATE
    	struct session_status;
    #endif

    	typedef boost::function<void(sha1_hash const&, std::vector<char>&
    		, error_code&)> user_load_function_t;

    	struct TORRENT_EXPORT session_handle
    	{
    		session_handle() : m_impl(NULL) {}

    		session_handle(aux::session_impl* impl)
    			: m_impl(impl)
    		{}

    		bool is_valid() const { return m_impl != NULL; }

    		// flags that determines which aspects of the session should be
    		// saved when calling save_state().
    		enum save_state_flags_t
    		{
    			// saves settings (i.e. the settings_pack)
    			save_settings =     0x001,

    			// saves dht_settings
    			save_dht_settings = 0x002,

    			// saves dht state such as nodes and node-id, possibly accelerating
    			// joining the DHT if provided at next session startup.
    			save_dht_state =    0x004,

    			// save pe_settings
    			save_encryption_settings = 0x020

    #ifndef TORRENT_NO_DEPRECATE
    			,
    			save_as_map TORRENT_DEPRECATED_ENUM =       0x040,
    			// saves RSS feeds
    			save_feeds TORRENT_DEPRECATED_ENUM =        0x080,
    			save_proxy TORRENT_DEPRECATED_ENUM =        0x008,
    			save_i2p_proxy TORRENT_DEPRECATED_ENUM =    0x010,
    			save_dht_proxy TORRENT_DEPRECATED_ENUM = 0x008, // save_proxy
    			save_peer_proxy TORRENT_DEPRECATED_ENUM = 0x008, // save_proxy
    			save_web_proxy TORRENT_DEPRECATED_ENUM = 0x008, // save_proxy
    			save_tracker_proxy TORRENT_DEPRECATED_ENUM = 0x008 // save_proxy
    #endif
    		};

relevance 2 | ../include/libtorrent/socks5_stream.hpp:142 | add async_connect() that takes a hostname and port as well

## add async_connect() that takes a hostname and port as well

#### ../include/libtorrent/socks5_stream.hpp:142

    		TORRENT_ASSERT(!is_ip_address(host.c_str()));
    		m_dst_name = host;
    		if (m_dst_name.size() > 255)
    			m_dst_name.resize(255);
    	}

    	void close(error_code& ec)
    	{
    		m_dst_name.clear();
    		proxy_base::close(ec);
    	}

    #ifndef BOOST_NO_EXCEPTIONS
    	void close()
    	{
    		m_dst_name.clear();
    		proxy_base::close();
    	}
    #endif

    	template <class Handler>
    	void async_connect(endpoint_type const& endpoint, Handler const& handler)
    	{
    		// make sure we don't try to connect to INADDR_ANY. binding is fine,
    		// and using a hostname is fine on SOCKS version 5.
    		TORRENT_ASSERT(endpoint.address() != address()
    			|| (!m_dst_name.empty() && m_version == 5));

    		m_remote_endpoint = endpoint;

    		// the connect is split up in the following steps:
    		// 1. resolve name of proxy server
    		// 2. connect to proxy server
    		// 3. if version == 5:
    		//   3.1 send SOCKS5 authentication method message
    		//   3.2 read SOCKS5 authentication response
    		//   3.3 send username+password
    		// 4. send SOCKS command message

    		// to avoid unnecessary copying of the handler,
    		// store it in a shaed_ptr
    		boost::shared_ptr<handler_type> h(new handler_type(handler));

    #if defined TORRENT_ASIO_DEBUGGING
    		add_outstanding_async("socks5_stream::name_lookup");
    #endif
    		tcp::resolver::query q(m_hostname, to_string(m_port).elems);
    		m_resolver.async_resolve(q, boost::bind(
    			&socks5_stream::name_lookup, this, _1, _2, h));
    	}

relevance 2 | ../include/libtorrent/tracker_manager.hpp:311 | this class probably doesn't need to have virtual functions.

## this class probably doesn't need to have virtual functions.

#### ../include/libtorrent/tracker_manager.hpp:311

    		int m_completion_timeout;

    		typedef mutex mutex_t;
    		mutable mutex_t m_mutex;

    		// used for timeouts
    		// this is set when the request has been sent
    		time_point m_start_time;

    		// this is set every time something is received
    		time_point m_read_time;

    		// the asio async operation
    		deadline_timer m_timeout;

    		int m_read_timeout;

    		bool m_abort;
    	};

    	struct TORRENT_EXTRA_EXPORT tracker_connection
    		: timeout_handler
    	{
    		tracker_connection(tracker_manager& man
    			, tracker_request const& req
    			, io_service& ios
    			, boost::weak_ptr<request_callback> r);

    		void update_transaction_id(boost::shared_ptr<udp_tracker_connection> c
    			, boost::uint64_t tid);

    		boost::shared_ptr<request_callback> requester() const;
    		virtual ~tracker_connection() {}

    		tracker_request const& tracker_req() const { return m_req; }

    		void fail(error_code const& ec, int code = -1, char const* msg = ""
    			, int interval = 0, int min_interval = 0);
    		virtual void start() = 0;
    		virtual void close();
    		address const& bind_interface() const { return m_req.bind_ip; }
    		void sent_bytes(int bytes);
    		void received_bytes(int bytes);
    		virtual bool on_receive(error_code const&, udp::endpoint const&
    			, char const* /* buf */, int /* size */) { return false; }
    		virtual bool on_receive_hostname(error_code const&
    			, char const* /* hostname */
    			, char const* /* buf */, int /* size */) { return false; }

    		boost::shared_ptr<tracker_connection> shared_from_this()
    		{

relevance 2 | ../include/libtorrent/aux_/session_impl.hpp:1173 | the throttling of saving resume data could probably be factored out into a separate class

## the throttling of saving resume data could probably be factored out into a separate class

#### ../include/libtorrent/aux_/session_impl.hpp:1173

    			// each second tick the timer takes a little
    			// bit longer than one second to trigger. The
    			// extra time it took is accumulated into this
    			// counter. Every time it exceeds 1000, torrents
    			// will tick their timers 2 seconds instead of one.
    			// this keeps the timers more accurate over time
    			// as a kind of "leap second" to adjust for the
    			// accumulated error
    			boost::uint16_t m_tick_residual;

    #ifndef TORRENT_DISABLE_LOGGING
    			virtual void session_log(char const* fmt, ...) const TORRENT_OVERRIDE TORRENT_FORMAT(2,3);
    			virtual void session_vlog(char const* fmt, va_list& va) const TORRENT_OVERRIDE TORRENT_FORMAT(2,0);

    			// this list of tracker loggers serves as tracker_callbacks when
    			// shutting down. This list is just here to keep them alive during
    			// whe shutting down process
    			std::list<boost::shared_ptr<tracker_logger> > m_tracker_loggers;
    #endif

    			virtual void queue_async_resume_data(boost::shared_ptr<torrent> const& t) TORRENT_OVERRIDE;
    			virtual void done_async_resume() TORRENT_OVERRIDE;
    			void async_resume_dispatched();

    			// state for keeping track of external IPs
    			external_ip m_external_ip;

    #ifndef TORRENT_DISABLE_EXTENSIONS
    			// this is a list to allow extensions to potentially remove themselves.
    			typedef std::list<boost::shared_ptr<plugin> > ses_extension_list_t;
    			ses_extension_list_t m_ses_extensions;

    			// the union of all session extensions' implemented_features(). This is
    			// used to exclude callbacks to the session extensions.
    			boost::uint32_t m_session_extension_features;

    			// std::string could be used for the query names if only all common
    			// implementations used SSO *glares at gcc*
    			struct extension_dht_query
    			{
    				boost::uint8_t query_len;
    				boost::array<char, max_dht_query_length> query;
    				dht_extension_handler_t handler;
    			};
    			typedef std::vector<extension_dht_query> m_extension_dht_queries_t;
    			m_extension_dht_queries_t m_extension_dht_queries;
    #endif

    			// if this function is set, it indicates that torrents are allowed
    			// to be unloaded. If it isn't, torrents will never be unloaded
    			user_load_function_t m_user_load_torrent;

relevance 2 | ../include/libtorrent/aux_/session_interface.hpp:135 | make this interface a lot smaller. It could be split up into several smaller interfaces. Each subsystem could then limit the size of the mock object to test it.

## make this interface a lot smaller. It could be split up into several smaller interfaces. Each subsystem could then limit the size of the mock object to test it.

#### ../include/libtorrent/aux_/session_interface.hpp:135

    	// a release build with logging disabled (which is the default) will
    	// not have this class at all
    	struct TORRENT_EXTRA_EXPORT session_logger
    	{
    #ifndef TORRENT_DISABLE_LOGGING
    		virtual void session_log(char const* fmt, ...) const TORRENT_FORMAT(2,3) = 0;
    		virtual void session_vlog(char const* fmt, va_list& va) const = 0;
    #endif

    #if TORRENT_USE_ASSERTS
    		virtual bool is_single_thread() const = 0;
    		virtual bool has_peer(peer_connection const* p) const = 0;
    		virtual bool any_torrent_has_peer(peer_connection const* p) const = 0;
    		virtual bool is_posting_torrent_updates() const = 0;
    #endif
    	protected:
    		~session_logger() {}
    	};
    #endif // TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS

    	struct TORRENT_EXTRA_EXPORT session_interface
    		: buffer_allocator_interface
    #if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
    		, session_logger
    #endif
    	{

relevance 2 | ../include/libtorrent/aux_/session_interface.hpp:144 | the IP voting mechanism should be factored out to its own class, not part of the session

## the IP voting mechanism should be factored out to its own class, not part of the session

#### ../include/libtorrent/aux_/session_interface.hpp:144

    		virtual void session_vlog(char const* fmt, va_list& va) const = 0;
    #endif

    #if TORRENT_USE_ASSERTS
    		virtual bool is_single_thread() const = 0;
    		virtual bool has_peer(peer_connection const* p) const = 0;
    		virtual bool any_torrent_has_peer(peer_connection const* p) const = 0;
    		virtual bool is_posting_torrent_updates() const = 0;
    #endif
    	protected:
    		~session_logger() {}
    	};
    #endif // TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS

    	struct TORRENT_EXTRA_EXPORT session_interface
    		: buffer_allocator_interface
    #if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
    		, session_logger
    #endif
    	{
    		enum
    		{
    			source_dht = 1,
    			source_peer = 2,
    			source_tracker = 4,
    			source_router = 8
    		};

    		virtual void set_external_address(address const& ip
    			, int source_type, address const& source) = 0;
    		virtual external_ip const& external_address() const = 0;

    		virtual disk_interface& disk_thread() = 0;

    		virtual alert_manager& alerts() = 0;

    		virtual torrent_peer_allocator_interface& get_peer_allocator() = 0;
    		virtual io_service& get_io_service() = 0;
    		virtual resolver_interface& get_resolver() = 0;

    		typedef boost::function<void(error_code const&, std::vector<address> const&)>
    			callback_t;

relevance 2 | ../include/libtorrent/aux_/session_interface.hpp:169 | remove this. There's already get_resolver()

## remove this. There's already get_resolver()

#### ../include/libtorrent/aux_/session_interface.hpp:169

    			source_peer = 2,
    			source_tracker = 4,
    			source_router = 8
    		};

    		virtual void set_external_address(address const& ip
    			, int source_type, address const& source) = 0;
    		virtual external_ip const& external_address() const = 0;

    		virtual disk_interface& disk_thread() = 0;

    		virtual alert_manager& alerts() = 0;

    		virtual torrent_peer_allocator_interface& get_peer_allocator() = 0;
    		virtual io_service& get_io_service() = 0;
    		virtual resolver_interface& get_resolver() = 0;

    		typedef boost::function<void(error_code const&, std::vector<address> const&)>
    			callback_t;

    		virtual void async_resolve(std::string const& host, int flags
    			, callback_t const& h) = 0;

    		virtual bool has_connection(peer_connection* p) const = 0;
    		virtual void insert_peer(boost::shared_ptr<peer_connection> const& c) = 0;

    		virtual void queue_async_resume_data(boost::shared_ptr<torrent> const& t) = 0;
    		virtual void done_async_resume() = 0;
    		virtual void evict_torrent(torrent* t) = 0;

    		virtual void remove_torrent(torrent_handle const& h, int options = 0) = 0;
    		virtual void remove_torrent_impl(boost::shared_ptr<torrent> tptr, int options) = 0;

    		// port filter
    		virtual port_filter const& get_port_filter() const = 0;
    		virtual void ban_ip(address addr) = 0;

    		virtual boost::uint16_t session_time() const = 0;

    		virtual bool is_paused() const = 0;
    		virtual bool is_aborted() const = 0;
    		virtual int num_uploads() const = 0;
    		virtual bool preemptive_unchoke() const = 0;
    		virtual void trigger_optimistic_unchoke() = 0;
    		virtual void trigger_unchoke() = 0;

    		virtual boost::weak_ptr<torrent> find_torrent(sha1_hash const& info_hash) const = 0;
    		virtual boost::weak_ptr<torrent> find_disconnect_candidate_torrent() const = 0;
    		virtual boost::shared_ptr<torrent> delay_load_torrent(sha1_hash const& info_hash
    			, peer_connection* pc) = 0;
    		virtual void insert_torrent(sha1_hash const& ih, boost::shared_ptr<torrent> const& t

relevance 2 | ../include/libtorrent/aux_/session_interface.hpp:224 | factor out the thread pool for socket jobs into a separate class used to (potentially) issue socket write calls onto multiple threads

## factor out the thread pool for socket jobs into a separate class used to (potentially) issue socket write calls onto multiple threads

#### ../include/libtorrent/aux_/session_interface.hpp:224

    		virtual int num_torrents() const = 0;

    		virtual peer_id const& get_peer_id() const = 0;

    		// cork a peer and schedule a delayed uncork
    		// does nothing if the peer is already corked
    		virtual void cork_burst(peer_connection* p) = 0;

    		virtual void close_connection(peer_connection* p, error_code const& ec) = 0;
    		virtual int num_connections() const = 0;

    		virtual char* allocate_buffer() = 0;
    		virtual void free_buffer(char* buf) = 0;
    		virtual int send_buffer_size() const = 0;

    		virtual void deferred_submit_jobs() = 0;

    		virtual boost::uint16_t listen_port() const = 0;
    		virtual boost::uint16_t ssl_listen_port() const = 0;

    		virtual void post_socket_job(socket_job& j) = 0;

    		// load the specified torrent. also evict one torrent, except
    		// for the one specified, if we are at the limit of loaded torrents
    		virtual bool load_torrent(torrent* t) = 0;

    		// bump the specified torrent to make it the most recently used one
    		// in the torrent LRU (i.e. the least likely to get unloaded)
    		virtual void bump_torrent(torrent* t, bool back = true) = 0;

    		// ask for which interface and port to bind outgoing peer connections on
    		virtual tcp::endpoint bind_outgoing_socket(socket_type& s, address const&
    			remote_address, error_code& ec) const = 0;
    		virtual bool verify_bound_address(address const& addr, bool utp
    			, error_code& ec) = 0;

    #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
    		virtual std::vector<boost::shared_ptr<torrent> > find_collection(
    			std::string const& collection) const = 0;
    #endif

relevance 1 | ../src/disk_io_thread.cpp:198 | it would be nice to have the number of threads be set dynamically

## it would be nice to have the number of threads be set dynamically

#### ../src/disk_io_thread.cpp:198

    		TORRENT_ASSERT(m_magic == 0x1337);
    #if TORRENT_USE_ASSERTS
    		m_magic = 0xdead;
    #endif
    	}

    	void disk_io_thread::abort(bool wait)
    	{
    		m_abort = true;
    		if (m_num_threads == 0)
    		{
    			abort_jobs();
    		}
    		else
    		{
    			set_num_threads(0, wait);
    		}
    	}

    	void disk_io_thread::set_num_threads(int i, bool wait)
    	{
    		TORRENT_ASSERT(m_magic == 0x1337);
    		if (i == m_num_threads) return;

    		if (i > m_num_threads)
    		{
    			while (m_num_threads < i)
    			{
    				int thread_id = (++m_num_threads) - 1;
    				thread_type_t type = generic_thread;

    				// this keeps the io_service::run() call blocked from returning.
    				// When shutting down, it's possible that the event queue is drained
    				// before the disk_io_thread has posted its last callback. When this
    				// happens, the io_service will have a pending callback from the
    				// disk_io_thread, but the event loop is not running. this means
    				// that the event is destructed after the disk_io_thread. If the
    				// event refers to a disk buffer it will try to free it, but the
    				// buffer pool won't exist anymore, and crash. This prevents that.
    				boost::shared_ptr<io_service::work> work =
    					boost::make_shared<io_service::work>(boost::ref(m_ios));

    				// the magic number 3 is also used in add_job()
    				// every 4:th thread is a hasher thread
    				if ((thread_id & 0x3) == 3) type = hasher_thread;
    				m_threads.push_back(boost::shared_ptr<thread>(
    					new thread(boost::bind(&disk_io_thread::thread_fun, this
    						, thread_id, type, work))));
    			}
    		}

relevance 1 | ../src/http_seed_connection.cpp:129 | in chunked encoding mode, this assert won't hold. the chunk headers should be subtracted from the receive_buffer_size

## in chunked encoding mode, this assert won't hold. the chunk headers should be subtracted from the receive_buffer_size

#### ../src/http_seed_connection.cpp:129

    	boost::optional<piece_block_progress>
    	http_seed_connection::downloading_piece_progress() const
    	{
    		if (m_requests.empty())
    			return boost::optional<piece_block_progress>();

    		boost::shared_ptr<torrent> t = associated_torrent().lock();
    		TORRENT_ASSERT(t);

    		piece_block_progress ret;

    		peer_request const& pr = m_requests.front();
    		ret.piece_index = pr.piece;
    		if (!m_parser.header_finished())
    		{
    			ret.bytes_downloaded = 0;
    		}
    		else
    		{
    			int receive_buffer_size = m_recv_buffer.get().left() - m_parser.body_start();
    			TORRENT_ASSERT_VAL(receive_buffer_size <= t->block_size(), receive_buffer_size);
    			ret.bytes_downloaded = t->block_size() - receive_buffer_size;
    		}
    		// this is used to make sure that the block_index stays within
    		// bounds. If the entire piece is downloaded, the block_index
    		// would otherwise point to one past the end
    		int correction = ret.bytes_downloaded ? -1 : 0;
    		ret.block_index = (pr.start + ret.bytes_downloaded + correction) / t->block_size();
    		ret.full_block_bytes = t->block_size();
    		const int last_piece = t->torrent_file().num_pieces() - 1;
    		if (ret.piece_index == last_piece && ret.block_index
    			== t->torrent_file().piece_size(last_piece) / t->block_size())
    			ret.full_block_bytes = t->torrent_file().piece_size(last_piece) % t->block_size();
    		return ret;
    	}

    	void http_seed_connection::write_request(peer_request const& r)
    	{
    		INVARIANT_CHECK;

    		boost::shared_ptr<torrent> t = associated_torrent().lock();
    		TORRENT_ASSERT(t);

    		TORRENT_ASSERT(t->valid_metadata());
    		// http_seeds don't support requesting more than one piece
    		// at a time
    		TORRENT_ASSERT(r.length <= t->torrent_file().piece_size(r.piece));

    		std::string request;
    		request.reserve(400);

relevance 1 | ../src/session_impl.cpp:5587 | report the proper address of the router as the source IP of this understanding of our external address, instead of the empty address

## report the proper address of the router as the source IP of this understanding of our external address, instead of the empty address

#### ../src/session_impl.cpp:5587

    		, int protocol, error_code const& ec, int map_transport)
    	{
    		TORRENT_ASSERT(is_single_thread());

    		TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);

    		if (mapping == m_udp_mapping[map_transport] && port != 0)
    		{
    			m_external_udp_port = port;
    			if (m_alerts.should_post<portmap_alert>())
    				m_alerts.emplace_alert<portmap_alert>(mapping, port
    					, map_transport, protocol == natpmp::udp
    					? portmap_alert::udp : portmap_alert::tcp);
    			return;
    		}

    		if (mapping == m_tcp_mapping[map_transport] && port != 0)
    		{
    			if (ip != address())
    			{
    				set_external_address(ip, source_router, address());
    			}

    			if (!m_listen_sockets.empty()) {
    				m_listen_sockets.front().external_address = ip;
    				m_listen_sockets.front().external_port = port;
    			}
    			if (m_alerts.should_post<portmap_alert>())
    				m_alerts.emplace_alert<portmap_alert>(mapping, port
    					, map_transport, protocol == natpmp::udp
    					? portmap_alert::udp : portmap_alert::tcp);
    			return;
    		}

    		if (ec)
    		{
    			if (m_alerts.should_post<portmap_error_alert>())
    				m_alerts.emplace_alert<portmap_error_alert>(mapping
    					, map_transport, ec);
    		}
    		else
    		{
    			if (m_alerts.should_post<portmap_alert>())
    				m_alerts.emplace_alert<portmap_alert>(mapping, port
    					, map_transport, protocol == natpmp::udp
    					? portmap_alert::udp : portmap_alert::tcp);
    		}
    	}

    #ifndef TORRENT_NO_DEPRECATE
    	session_status session_impl::status() const

relevance 1 | ../src/torrent.cpp:1259 | make this depend on the error and on the filesystem the files are being downloaded to. If the error is no_space_left_on_device and the filesystem doesn't support sparse files, only zero the priorities of the pieces that are at the tails of all files, leaving everything up to the highest written piece in each file

## make this depend on the error and on the filesystem the files are being downloaded to. If the error is no_space_left_on_device and the filesystem doesn't support sparse files, only zero the priorities of the pieces that are at the tails of all files, leaving everything up to the highest written piece in each file

#### ../src/torrent.cpp:1259

    		// notify the user of the error
    		if (alerts().should_post<file_error_alert>())
    			alerts().emplace_alert<file_error_alert>(j->error.ec
    				, resolve_filename(j->error.file), j->error.operation_str(), get_handle());

    		// if a write operation failed, and future writes are likely to
    		// fail, while reads may succeed, just set the torrent to upload mode
    		// if we make an incorrect assumption here, it's not the end of the
    		// world, if we ever issue a read request and it fails as well, we
    		// won't get in here and we'll actually end up pausing the torrent
    		if (j->action == disk_io_job::write
    			&& (j->error.ec == boost::system::errc::read_only_file_system
    			|| j->error.ec == boost::system::errc::permission_denied
    			|| j->error.ec == boost::system::errc::operation_not_permitted
    			|| j->error.ec == boost::system::errc::no_space_on_device
    			|| j->error.ec == boost::system::errc::file_too_large))
    		{
    			// if we failed to write, stop downloading and just
    			// keep seeding.
    			set_upload_mode(true);
    			return;
    		}

    		// put the torrent in an error-state
    		set_error(j->error.ec, j->error.file);

    		// if the error appears to be more serious than a full disk, just pause the torrent
    		pause();
    	}

    	void torrent::on_piece_fail_sync(disk_io_job const* j, piece_block b)
    	{
    		TORRENT_UNUSED(j);
    		TORRENT_UNUSED(b);

    		if (m_abort) return;

    		update_gauge();
    		// some peers that previously was no longer interesting may
    		// now have become interesting, since we lack this one piece now.
    		for (peer_iterator i = begin(); i != end();)
    		{
    			peer_connection* p = *i;
    			// update_interest may disconnect the peer and
    			// invalidate the iterator
    			++i;
    			// no need to do anything with peers that
    			// already are interested. Gaining a piece may
    			// only make uninteresting peers interesting again.
    			if (p->is_interesting()) continue;

relevance 1 | ../src/torrent.cpp:7355 | save the send_stats state instead of throwing them away it may pose an issue when downgrading though

## save the send_stats state instead of throwing them away it may pose an issue when downgrading though

#### ../src/torrent.cpp:7355

    					for (int k = 0; k < bits; ++k)
    						v |= (info[j*8+k].state == piece_picker::block_info::state_finished)
    						? (1 << k) : 0;
    					bitmask.append(1, v);
    					TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
    				}
    				piece_struct["bitmask"] = bitmask;
    				// push the struct onto the unfinished-piece list
    				up.push_back(piece_struct);
    			}
    		}

    		// save trackers
    		entry::list_type& tr_list = ret["trackers"].list();
    		tr_list.push_back(entry::list_type());
    		int tier = 0;
    		for (std::vector<announce_entry>::const_iterator i = m_trackers.begin()
    			, end(m_trackers.end()); i != end; ++i)
    		{
    			// don't save trackers we can't trust
    			if (i->send_stats == false) continue;
    			if (i->tier == tier)
    			{
    				tr_list.back().list().push_back(i->url);
    			}
    			else
    			{
    				tr_list.push_back(entry::list_t);
    				tr_list.back().list().push_back(i->url);
    				tier = i->tier;
    			}
    		}

    		// save web seeds
    		if (!m_web_seeds.empty())
    		{
    			entry::list_type& url_list = ret["url-list"].list();
    			entry::list_type& httpseed_list = ret["httpseeds"].list();
    			for (std::list<web_seed_t>::const_iterator i = m_web_seeds.begin()
    				, end(m_web_seeds.end()); i != end; ++i)
    			{
    				if (i->removed) continue;
    				if (i->type == web_seed_entry::url_seed)
    					url_list.push_back(i->url);
    				else if (i->type == web_seed_entry::http_seed)
    					httpseed_list.push_back(i->url);
    			}
    		}

    		// write have bitmask
    		// the pieces string has one byte per piece. Each

relevance 1 | ../src/torrent.cpp:8606 | should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though

## should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though

#### ../src/torrent.cpp:8606

    		set_state(torrent_status::finished);
    		set_queue_position(-1);

    		m_became_finished = m_ses.session_time();

    		// we have to call completed() before we start
    		// disconnecting peers, since there's an assert
    		// to make sure we're cleared the piece picker
    		if (is_seed()) completed();

    		send_upload_only();
    		state_updated();

    		if (m_completed_time == 0)
    			m_completed_time = time(0);

    		// disconnect all seeds
    		if (settings().get_bool(settings_pack::close_redundant_connections))
    		{
    			std::vector<peer_connection*> seeds;
    			for (peer_iterator i = m_connections.begin();
    				i != m_connections.end(); ++i)
    			{
    				TORRENT_INCREMENT(m_iterating_connections);
    				peer_connection* p = *i;
    				TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
    				if (p->upload_only())
    				{
    #ifndef TORRENT_DISABLE_LOGGING
    					p->peer_log(peer_log_alert::info, "SEED", "CLOSING CONNECTION");
    #endif
    					seeds.push_back(p);
    				}
    			}
    			std::for_each(seeds.begin(), seeds.end()
    				, boost::bind(&peer_connection::disconnect, _1, errors::torrent_finished
    				, op_bittorrent, 0));
    		}

    		if (m_abort) return;

    		update_want_peers();

    		if (m_storage)
    		{
    			// we need to keep the object alive during this operation
    			inc_refcount("release_files");
    			m_ses.disk_thread().async_release_files(m_storage.get()
    				, boost::bind(&torrent::on_cache_flushed, shared_from_this(), _1));
    		}

relevance 1 | ../include/libtorrent/ip_voter.hpp:124 | instead, have one instance per possible subnet, global IPv4, global IPv6, loopback, 192.168.x.x, 10.x.x.x, etc.

## instead, have one instance per possible subnet, global IPv4, global IPv6, loopback, 192.168.x.x, 10.x.x.x, etc.

#### ../include/libtorrent/ip_voter.hpp:124

    		// away all the votes and started from scratch, in case
    		// our IP has changed
    		time_point m_last_rotate;
    	};

    	// this keeps track of multiple external IPs (for now, just IPv6 and IPv4, but
    	// it could be extended to deal with loopback and local network addresses as well)
    	struct TORRENT_EXTRA_EXPORT external_ip
    	{
    		// returns true if a different IP is the top vote now
    		// i.e. we changed our idea of what our external IP is
    		bool cast_vote(address const& ip, int source_type, address const& source);

    		// the external IP as it would be observed from `ip`
    		address external_address(address const& ip) const;

    	private:

    		// for now, assume one external IPv4 and one external IPv6 address
    		// 0 = IPv4 1 = IPv6
    		ip_voter m_vote_group[2];
    	};

    }

    #endif

relevance 0 | ../test/test_block_cache.cpp:469 | test try_evict_blocks

## test try_evict_blocks

#### ../test/test_block_cache.cpp:469

relevance 0 | ../test/test_block_cache.cpp:470 | test evicting volatile pieces, to see them be removed

## test evicting volatile pieces, to see them be removed

#### ../test/test_block_cache.cpp:470

relevance 0 | ../test/test_block_cache.cpp:471 | test evicting dirty pieces

## test evicting dirty pieces

#### ../test/test_block_cache.cpp:471

relevance 0 | ../test/test_block_cache.cpp:472 | test free_piece

## test free_piece

#### ../test/test_block_cache.cpp:472

relevance 0 | ../test/test_block_cache.cpp:473 | test abort_dirty

## test abort_dirty

#### ../test/test_block_cache.cpp:473

relevance 0 | ../test/test_block_cache.cpp:474 | test unaligned reads

## test unaligned reads

#### ../test/test_block_cache.cpp:474

    	// it's supposed to be a cache hit
    	TEST_CHECK(ret >= 0);
    	// return the reference to the buffer we just read
    	RETURN_BUFFER;

    	tailqueue<disk_io_job> jobs;
    	bc.clear(jobs);
    }

    TORRENT_TEST(block_cache)
    {
    	test_write();
    	test_flush();
    	test_insert();
    	test_evict();
    	test_arc_promote();
    	test_arc_unghost();
    	test_iovec();
    	test_unaligned_read();

    }

    TORRENT_TEST(delete_piece)
    {
    	TEST_SETUP;

    	TEST_CHECK(bc.num_pieces() == 0);

    	INSERT(0, 0);

    	TEST_CHECK(bc.num_pieces() == 1);

    	rj.action = disk_io_job::read;
    	rj.d.io.offset = 0x2000;
    	rj.d.io.buffer_size = 0x4000;
    	rj.piece = 0;
    	rj.storage = pm;
    	rj.requester = (void*)1;
    	rj.buffer.disk_block = 0;
    	ret = bc.try_read(&rj);

    	cached_piece_entry* pe_ = bc.find_piece(pm.get(), 0);
    	bc.mark_for_eviction(pe_, block_cache::disallow_ghost);

    	TEST_CHECK(bc.num_pieces() == 0);
    }

relevance 0 | ../test/test_bloom_filter.cpp:130 | test size()

## test size()

#### ../test/test_bloom_filter.cpp:130

relevance 0 | ../test/test_bloom_filter.cpp:131 | test clear()

## test clear()

#### ../test/test_bloom_filter.cpp:131

    	TEST_EQUAL(memcmp(bits_out.c_str(), bits, 4), 0);

    	sha1_hash k( "\x01\x00\x02\x00                ");
    	TEST_CHECK(!filter.find(k));
    	filter.set(k);
    	TEST_CHECK(filter.find(k));

    	boost::uint8_t compare[4] = { 0x16, 0xff, 0x55, 0xaa};

    	bits_out = filter.to_string();
    	TEST_EQUAL(memcmp(compare, bits_out.c_str(), 4), 0);
    }

    TORRENT_TEST(bloom_filter)
    {
    	test_set_and_get();
    	test_set_bits();
    	test_count_zeroes();
    	test_to_from_string();

    }

relevance 0 | ../test/test_dht.cpp:103 | ideally the mock_socket would contain this queue of packets, to make tests independent

## ideally the mock_socket would contain this queue of packets, to make tests independent

#### ../test/test_dht.cpp:103

    		carry = sum > 255;
    	}
    }

    void node_push_back(void* userdata, libtorrent::dht::node_entry const& n)
    {
    	using namespace libtorrent::dht;
    	std::vector<node_entry>* nv = (std::vector<node_entry>*)userdata;
    	nv->push_back(n);
    }

    static void nop(void* userdata, libtorrent::dht::node_entry const& n) {}

    std::list<std::pair<udp::endpoint, entry> > g_sent_packets;

    struct mock_socket : udp_socket_interface
    {
    	bool has_quota() { return true; }
    	bool send_packet(entry& msg, udp::endpoint const& ep, int flags)
    	{
    		g_sent_packets.push_back(std::make_pair(ep, msg));
    		return true;
    	}
    };

    sha1_hash generate_next()
    {
    	sha1_hash ret;
    	for (int i = 0; i < 20; ++i) ret[i] = rand() & 0xff;
    	return ret;
    }

    boost::array<char, 64> generate_key()
    {
    	boost::array<char, 64> ret;
    	for (int i = 0; i < 64; ++i) ret[i] = rand() & 0xff;
    	return ret;
    }

    static const std::string no;

    std::list<std::pair<udp::endpoint, entry> >::iterator
    find_packet(udp::endpoint ep)
    {
    	return std::find_if(g_sent_packets.begin(), g_sent_packets.end()
    		, boost::bind(&std::pair<udp::endpoint, entry>::first, _1) == ep);
    }

    void lazy_from_entry(entry const& e, bdecode_node& l)
    {
    	error_code ec;

relevance 0 | ../test/test_dht.cpp:420 | check to make sure the "best" items are stored

## check to make sure the "best" items are stored

#### ../test/test_dht.cpp:420

    		key_desc_t desc[] =
    		{
    			{ "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
    				{ "v", bdecode_node::dict_t, 0, 0},
    				{ "id", bdecode_node::string_t, 20, key_desc_t::last_child},
    			{ "y", bdecode_node::string_t, 1, 0},
    		};

    		bdecode_node parsed[4];
    		char error_string[200];

    		int ret = verify_message(response, desc, parsed, error_string
    			, sizeof(error_string));
    		if (ret)
    		{
    			items_num.insert(items_num.begin(), j);
    		}
    	}

    	TEST_EQUAL(items_num.size(), 4);
    }

    int sum_distance_exp(int s, node_entry const& e, node_id const& ref)
    {
    	return s + distance_exp(e.id, ref);
    }

    std::vector<tcp::endpoint> g_got_peers;

    void get_peers_cb(std::vector<tcp::endpoint> const& peers)
    {
    	g_got_peers.insert(g_got_peers.end(), peers.begin(), peers.end());
    }

    std::vector<dht::item> g_got_items;
    dht::item g_put_item;
    int g_put_count;

    void get_mutable_item_cb(dht::item const& i, bool a)
    {
    	if (!a) return;
    	if (!i.empty())
    		g_got_items.push_back(i);
    }

    void put_mutable_item_data_cb(dht::item& i)
    {
    	if (!i.empty())
    		g_got_items.push_back(i);

relevance 0 | ../test/test_dht.cpp:513 | test obfuscated_get_peers

## test obfuscated_get_peers

#### ../test/test_dht.cpp:513

relevance 0 | ../test/test_fast_extension.cpp:1020 | test sending invalid requests (out of bound piece index, offsets and sizes)

## test sending invalid requests (out of bound piece index, offsets and sizes)

#### ../test/test_fast_extension.cpp:1020

    			TEST_ERROR("received bitfield from seed despite advertising support for FAST");
    			break;
    		}
    	}
    }

    TORRENT_TEST(outgoing_have_all)
    {
    	std::cerr << "\n === test outgoing have-all ===\n" << std::endl;
    	have_all_test(true);
    }

    TORRENT_TEST(incoming_have_all)
    {
    	std::cerr << "\n === test outgoing have-all ===\n" << std::endl;
    	have_all_test(false);
    }

    #endif // TORRENT_DISABLE_EXTENSIONS

relevance 0 | ../test/test_file_progress.cpp:109 | test the update function too

## test the update function too

#### ../test/test_file_progress.cpp:109

    	for (int idx = 0; idx < fs.num_pieces(); ++idx)
    	{
    		piece_picker picker;
    		picker.init(4, fs.total_size() % 4, fs.num_pieces());
    		picker.we_have(idx);

    		std::vector<boost::int64_t> vec;
    		aux::file_progress fp;

    		fp.init(picker, fs);
    		fp.export_progress(vec);

    		boost::uint64_t sum = 0;
    		for (int i = 0; i < int(vec.size()); ++i)
    			sum += vec[i];

    		TEST_EQUAL(int(sum), fs.piece_size(idx));
    	}
    }

relevance 0 | ../test/test_file_storage.cpp:307 | add more optimize() tests

## add more optimize() tests

#### ../test/test_file_storage.cpp:307

relevance 0 | ../test/test_file_storage.cpp:308 | test map_block

## test map_block

#### ../test/test_file_storage.cpp:308

relevance 0 | ../test/test_file_storage.cpp:309 | test piece_size(int piece)

## test piece_size(int piece)

#### ../test/test_file_storage.cpp:309

relevance 0 | ../test/test_file_storage.cpp:310 | test file_index_at_offset

## test file_index_at_offset

#### ../test/test_file_storage.cpp:310

relevance 0 | ../test/test_file_storage.cpp:311 | test file attributes

## test file attributes

#### ../test/test_file_storage.cpp:311

relevance 0 | ../test/test_file_storage.cpp:312 | test symlinks

## test symlinks

#### ../test/test_file_storage.cpp:312

relevance 0 | ../test/test_file_storage.cpp:313 | test pad_files

## test pad_files

#### ../test/test_file_storage.cpp:313

relevance 0 | ../test/test_file_storage.cpp:314 | test reorder_file (make sure internal_file_entry::swap() is used)

## test reorder_file (make sure internal_file_entry::swap() is used)

#### ../test/test_file_storage.cpp:314

    	// place that as part of the padding

    	TEST_EQUAL(fs.num_files(), 4);

    	TEST_EQUAL(fs.file_size(0), 1001);
    	TEST_EQUAL(fs.file_name(0), "3");
    	TEST_EQUAL(fs.pad_file_at(0), false);

    	TEST_EQUAL(fs.file_size(1), 1);
    	TEST_EQUAL(fs.file_name(1), "1");
    	TEST_EQUAL(fs.pad_file_at(1), false);

    	TEST_EQUAL(fs.file_size(2), 1024 - (1001 + 1));
    	TEST_EQUAL(fs.pad_file_at(2), true);

    	TEST_EQUAL(fs.file_size(3), 1000);
    	TEST_EQUAL(fs.file_name(3), "2");
    	TEST_EQUAL(fs.pad_file_at(3), false);
    }

relevance 0 | ../test/test_peer_list.cpp:937 | test erasing peers

## test erasing peers

#### ../test/test_peer_list.cpp:937

relevance 0 | ../test/test_peer_list.cpp:938 | test update_peer_port with allow_multiple_connections_per_ip and without

## test update_peer_port with allow_multiple_connections_per_ip and without

#### ../test/test_peer_list.cpp:938

relevance 0 | ../test/test_peer_list.cpp:939 | test add i2p peers

## test add i2p peers

#### ../test/test_peer_list.cpp:939

relevance 0 | ../test/test_peer_list.cpp:940 | test allow_i2p_mixed

## test allow_i2p_mixed

#### ../test/test_peer_list.cpp:940

relevance 0 | ../test/test_peer_list.cpp:941 | test insert_peer failing with all error conditions

## test insert_peer failing with all error conditions

#### ../test/test_peer_list.cpp:941

relevance 0 | ../test/test_peer_list.cpp:942 | test IPv6

## test IPv6

#### ../test/test_peer_list.cpp:942

relevance 0 | ../test/test_peer_list.cpp:943 | test connect_to_peer() failing

## test connect_to_peer() failing

#### ../test/test_peer_list.cpp:943

relevance 0 | ../test/test_peer_list.cpp:944 | test connection_closed

## test connection_closed

#### ../test/test_peer_list.cpp:944

relevance 0 | ../test/test_peer_list.cpp:945 | connect candidates recalculation when incrementing failcount

## connect candidates recalculation when incrementing failcount

#### ../test/test_peer_list.cpp:945

    	torrent_peer* peer4 = add_peer(p, st, ep("10.0.0.4", 8080));
    	TEST_CHECK(peer4);
    	TEST_EQUAL(p.num_peers(), 4);
    	torrent_peer* peer5 = add_peer(p, st, ep("10.0.0.5", 8080));
    	TEST_CHECK(peer5);
    	TEST_EQUAL(p.num_peers(), 5);
    	torrent_peer* peer6 = p.add_peer(ep("10.0.0.6", 8080), 0, 0, &st);
    	TEST_CHECK(peer6 == NULL);
    	TEST_EQUAL(p.num_peers(), 5);

    	// one of the connection should have been removed
    	TEST_EQUAL(has_peer(p, ep("10.0.0.1", 8080))
    		+ has_peer(p, ep("10.0.0.2", 8080))
    		+ has_peer(p, ep("10.0.0.3", 8080))
    		+ has_peer(p, ep("10.0.0.4", 8080))
    		+ has_peer(p, ep("10.0.0.5", 8080))
    		+ has_peer(p, ep("10.0.0.6", 8080))
    		, 5);
    }

relevance 0 | ../test/test_resolve_links.cpp:80 | test files with different piece size (negative test)

## test files with different piece size (negative test)

#### ../test/test_resolve_links.cpp:80

    	{ "test2", "test1_pad_files", 0},
    	{ "test3", "test1_pad_files", 0},
    	{ "test2", "test1_single", 0},

    	// these are all padded. The first small file will accidentally also
    	// match, even though it's not tail padded, the following file is identical
    	{ "test2_pad_files", "test1_pad_files", 2},
    	{ "test3_pad_files", "test1_pad_files", 2},
    	{ "test3_pad_files", "test2_pad_files", 2},
    	{ "test1_pad_files", "test2_pad_files", 2},
    	{ "test1_pad_files", "test3_pad_files", 2},
    	{ "test2_pad_files", "test3_pad_files", 2},

    	// one might expect this to work, but since the tail of the single file
    	// torrent is not padded, the last piece hash won't match
    	{ "test1_pad_files", "test1_single", 0},

    	// if it's padded on the other hand, it will work
    	{ "test1_pad_files", "test1_single_padded", 1},

    };

relevance 0 | ../test/test_resolve_links.cpp:83 | it would be nice to test resolving of more than just 2 files as well. like 3 single file torrents merged into one, resolving all 3 files.

## it would be nice to test resolving of more than just 2 files as well. like 3 single file torrents merged into one, resolving all 3 files.

#### ../test/test_resolve_links.cpp:83

    	{ "test2", "test1_single", 0},

    	// these are all padded. The first small file will accidentally also
    	// match, even though it's not tail padded, the following file is identical
    	{ "test2_pad_files", "test1_pad_files", 2},
    	{ "test3_pad_files", "test1_pad_files", 2},
    	{ "test3_pad_files", "test2_pad_files", 2},
    	{ "test1_pad_files", "test2_pad_files", 2},
    	{ "test1_pad_files", "test3_pad_files", 2},
    	{ "test2_pad_files", "test3_pad_files", 2},

    	// one might expect this to work, but since the tail of the single file
    	// torrent is not padded, the last piece hash won't match
    	{ "test1_pad_files", "test1_single", 0},

    	// if it's padded on the other hand, it will work
    	{ "test1_pad_files", "test1_single_padded", 1},

    };

    TORRENT_TEST(resolve_links)
    {

    #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
    	std::string path = combine_path(parent_path(current_working_directory())
    		, "mutable_test_torrents");

    	for (int i = 0; i < int(sizeof(test_torrents)/sizeof(test_torrents[0])); ++i)
    	{
    		test_torrent_t const& e = test_torrents[i];

    		std::string p = combine_path(path, e.filename1) + ".torrent";
    		fprintf(stdout, "loading %s\n", p.c_str());
    		boost::shared_ptr<torrent_info> ti1 = boost::make_shared<torrent_info>(p);

    		p = combine_path(path, e.filename2) + ".torrent";
    		fprintf(stdout, "loading %s\n", p.c_str());
    		boost::shared_ptr<torrent_info> ti2 = boost::make_shared<torrent_info>(p);

    		fprintf(stdout, "resolving\n");
    		resolve_links l(ti1);
    		l.match(ti2, ".");

    		std::vector<resolve_links::link_t> const& links = l.get_links();

    		int num_matches = std::count_if(links.begin(), links.end()
    			, boost::bind(&resolve_links::link_t::ti, _1));

    		// some debug output in case the test fails
    		if (num_matches > e.expected_matches)

relevance 0 | ../test/test_resume.cpp:292 | test what happens when loading a resume file with both piece priorities and file priorities (file prio should take presedence)

## test what happens when loading a resume file with both piece priorities and file priorities (file prio should take presedence)

#### ../test/test_resume.cpp:292

    		fprintf(stderr, "%s\n", ra->resume_data->to_string().c_str());
    		entry::string_type prios = (*ra->resume_data)["piece_priority"].string();
    		TEST_EQUAL(int(prios.size()), ti->num_pieces());
    		TEST_EQUAL(prios[0], '\0');
    		TEST_EQUAL(prios[1], '\x04');
    		TEST_EQUAL(prios[ti->num_pieces()-1], '\0');

    		bencode(std::back_inserter(p.resume_data), *ra->resume_data);
    	}

    	ses.remove_torrent(h);

    	// now, make sure the piece priorities are loaded correctly
    	h = ses.add_torrent(p);

    	TEST_EQUAL(h.piece_priority(0), 0);
    	TEST_EQUAL(h.piece_priority(1), 4);
    	TEST_EQUAL(h.piece_priority(ti->num_pieces()-1), 0);
    }

relevance 0 | ../test/test_resume.cpp:295 | make sure a resume file only ever contain file priorities OR piece priorities. Never both.

## make sure a resume file only ever contain file priorities OR piece priorities. Never both.

#### ../test/test_resume.cpp:295

    		entry::string_type prios = (*ra->resume_data)["piece_priority"].string();
    		TEST_EQUAL(int(prios.size()), ti->num_pieces());
    		TEST_EQUAL(prios[0], '\0');
    		TEST_EQUAL(prios[1], '\x04');
    		TEST_EQUAL(prios[ti->num_pieces()-1], '\0');

    		bencode(std::back_inserter(p.resume_data), *ra->resume_data);
    	}

    	ses.remove_torrent(h);

    	// now, make sure the piece priorities are loaded correctly
    	h = ses.add_torrent(p);

    	TEST_EQUAL(h.piece_priority(0), 0);
    	TEST_EQUAL(h.piece_priority(1), 4);
    	TEST_EQUAL(h.piece_priority(ti->num_pieces()-1), 0);
    }

relevance 0 | ../test/test_resume.cpp:298 | generally save

## generally save

#### ../test/test_resume.cpp:298

    		TEST_EQUAL(int(prios.size()), ti->num_pieces());
    		TEST_EQUAL(prios[0], '\0');
    		TEST_EQUAL(prios[1], '\x04');
    		TEST_EQUAL(prios[ti->num_pieces()-1], '\0');

    		bencode(std::back_inserter(p.resume_data), *ra->resume_data);
    	}

    	ses.remove_torrent(h);

    	// now, make sure the piece priorities are loaded correctly
    	h = ses.add_torrent(p);

    	TEST_EQUAL(h.piece_priority(0), 0);
    	TEST_EQUAL(h.piece_priority(1), 4);
    	TEST_EQUAL(h.piece_priority(ti->num_pieces()-1), 0);
    }

    TORRENT_TEST(file_priorities_default)
    {
    	lt::session ses(settings());
    	std::vector<int> file_priorities = test_resume_flags(ses, 0, "", "").file_priorities();

    	TEST_EQUAL(file_priorities.size(), 3);
    	TEST_EQUAL(file_priorities[0], 4);
    	TEST_EQUAL(file_priorities[1], 4);
    	TEST_EQUAL(file_priorities[2], 4);
    }

    // As long as the add_torrent_params priorities are empty, the file_priorities
    // from the resume data should take effect
    TORRENT_TEST(file_priorities_in_resume)
    {
    	lt::session ses(settings());
    	std::vector<int> file_priorities = test_resume_flags(ses, 0, "", "123").file_priorities();

    	TEST_EQUAL(file_priorities.size(), 3);
    	TEST_EQUAL(file_priorities[0], 1);
    	TEST_EQUAL(file_priorities[1], 2);
    	TEST_EQUAL(file_priorities[2], 3);
    }

    // if both resume data and add_torrent_params has file_priorities, the
    // add_torrent_params one take precedence
    TORRENT_TEST(file_priorities_in_resume_and_params)
    {
    	lt::session ses(settings());
    	std::vector<int> file_priorities = test_resume_flags(ses, 0, "456", "123").file_priorities();

relevance 0 | ../test/test_resume.cpp:794 | test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance

## test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance

#### ../test/test_resume.cpp:794

    	lt::session ses(settings());
    	// resume data overrides the paused flag
    	torrent_status s = test_resume_flags(ses, add_torrent_params::flag_paused).status();
    	default_tests(s);
    #ifdef TORRENT_WINDOWS
    	TEST_EQUAL(s.save_path, "c:\\add_torrent_params save_path");
    #else
    	TEST_EQUAL(s.save_path, "/add_torrent_params save_path");
    #endif
    	TEST_EQUAL(s.sequential_download, false);
    	TEST_EQUAL(s.paused, false);
    	TEST_EQUAL(s.auto_managed, false);
    	TEST_EQUAL(s.seed_mode, false);
    	TEST_EQUAL(s.super_seeding, false);
    	TEST_EQUAL(s.share_mode, false);
    	TEST_EQUAL(s.upload_mode, false);
    	TEST_EQUAL(s.ip_filter_applies, false);
    	TEST_EQUAL(s.connections_limit, 1345);
    	TEST_EQUAL(s.uploads_limit, 1346);

    }

    TORRENT_TEST(url_seed_resume_data)
    {
    	// merge url seeds with resume data
    	fprintf(stderr, "flags: merge_resume_http_seeds\n");
    	lt::session ses(settings());
    	torrent_handle h = test_resume_flags(ses,
    		add_torrent_params::flag_merge_resume_http_seeds);
    	std::set<std::string> us = h.url_seeds();
    	std::set<std::string> ws = h.http_seeds();

    	TEST_EQUAL(us.size(), 3);
    	TEST_EQUAL(std::count(us.begin(), us.end()
    		, "http://add_torrent_params_url_seed.com"), 1);
    	TEST_EQUAL(std::count(us.begin(), us.end()
    		, "http://torrent_file_url_seed.com/"), 1);
    	TEST_EQUAL(std::count(us.begin(), us.end()
    		, "http://resume_data_url_seed.com/"), 1);

    	TEST_EQUAL(ws.size(), 1);
    	TEST_EQUAL(std::count(ws.begin(), ws.end()
    		, "http://resume_data_http_seed.com"), 1);
    }

    TORRENT_TEST(resume_override_torrent)
    {
    	// resume data overrides the .torrent_file
    	fprintf(stderr, "flags: no merge_resume_http_seed\n");
    	lt::session ses(settings());
    	torrent_handle h = test_resume_flags(ses,

relevance 0 | ../test/test_settings_pack.cpp:227 | load_pack_from_dict

## load_pack_from_dict

#### ../test/test_settings_pack.cpp:227

    	TEST_EQUAL(settings_pack::bool_type_base, 0x8000);
    	TEST_EQUAL(settings_pack::type_mask, 0xc000);

    	// strings
    	TEST_EQUAL(settings_pack::outgoing_interfaces, settings_pack::string_type_base + 4);
    	TEST_EQUAL(settings_pack::dht_bootstrap_nodes, settings_pack::string_type_base + 11);

    	// bool
    	TEST_EQUAL(settings_pack::lazy_bitfields, settings_pack::bool_type_base + 3);
    	TEST_EQUAL(settings_pack::use_read_cache, settings_pack::bool_type_base + 7);
    	TEST_EQUAL(settings_pack::proxy_tracker_connections, settings_pack::bool_type_base + 68);

    	// ints
    	TEST_EQUAL(settings_pack::max_suggest_pieces, settings_pack::int_type_base + 66);
    	TEST_EQUAL(settings_pack::connections_slack, settings_pack::int_type_base + 86);
    	TEST_EQUAL(settings_pack::aio_threads, settings_pack::int_type_base + 104);
    	TEST_EQUAL(settings_pack::max_http_recv_buffer_size, settings_pack::int_type_base + 115);
    	TEST_EQUAL(settings_pack::web_seed_name_lookup_retry, settings_pack::int_type_base + 128);
    }

relevance 0 | ../test/test_ssl.cpp:393 | test using a signed certificate with the wrong info-hash in DN

## test using a signed certificate with the wrong info-hash in DN

#### ../test/test_ssl.cpp:393

    	// in verifying peers
    	ctx.set_verify_mode(context::verify_none, ec);
    	if (ec)
    	{
    		fprintf(stderr, "Failed to set SSL verify mode: %s\n"
    			, ec.message().c_str());
    		TEST_CHECK(!ec);
    		return false;
    	}

    	std::string certificate = combine_path("..", combine_path("ssl", "peer_certificate.pem"));
    	std::string private_key = combine_path("..", combine_path("ssl", "peer_private_key.pem"));
    	std::string dh_params = combine_path("..", combine_path("ssl", "dhparams.pem"));

    	if (flags & invalid_certificate)
    	{
    		certificate = combine_path("..", combine_path("ssl", "invalid_peer_certificate.pem"));
    		private_key = combine_path("..", combine_path("ssl", "invalid_peer_private_key.pem"));
    	}

    	if (flags & (valid_certificate | invalid_certificate))
    	{
    		fprintf(stderr, "set_password_callback\n");
    		ctx.set_password_callback(boost::bind(&password_callback, _1, _2, "test"), ec);
    		if (ec)
    		{
    			fprintf(stderr, "Failed to set certificate password callback: %s\n"
    				, ec.message().c_str());
    			TEST_CHECK(!ec);
    			return false;
    		}
    		fprintf(stderr, "use_certificate_file \"%s\"\n", certificate.c_str());
    		ctx.use_certificate_file(certificate, context::pem, ec);
    		if (ec)
    		{
    			fprintf(stderr, "Failed to set certificate file: %s\n"
    				, ec.message().c_str());
    			TEST_CHECK(!ec);
    			return false;
    		}
    		fprintf(stderr, "use_private_key_file \"%s\"\n", private_key.c_str());
    		ctx.use_private_key_file(private_key, context::pem, ec);
    		if (ec)
    		{
    			fprintf(stderr, "Failed to set private key: %s\n"
    				, ec.message().c_str());
    			TEST_CHECK(!ec);
    			return false;
    		}
    		fprintf(stderr, "use_tmp_dh_file \"%s\"\n", dh_params.c_str());

relevance 0 | ../test/test_ssl.cpp:491 | also test using a hash that refers to a valid torrent but that differs from the SNI hash

## also test using a hash that refers to a valid torrent but that differs from the SNI hash

#### ../test/test_ssl.cpp:491

    	print_alerts(ses1, "ses1", true, true, true, &on_alert);
    	if (ec)
    	{
    		fprintf(stderr, "Failed SSL handshake: %s\n"
    			, ec.message().c_str());
    		return false;
    	}

    	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
    		"                    " // space for info-hash
    		"aaaaaaaaaaaaaaaaaaaa" // peer-id
    		"\0\0\0\x01\x02"; // interested

    	// fill in the info-hash
    	if (flags & valid_bittorrent_hash)
    	{
    		std::memcpy(handshake + 28, &t->info_hash()[0], 20);
    	}
    	else
    	{
    		std::generate(handshake + 28, handshake + 48, &rand);
    	}

    	// fill in the peer-id
    	std::generate(handshake + 48, handshake + 68, &rand);

    	fprintf(stderr, "bittorrent handshake\n");
    	boost::asio::write(ssl_sock, boost::asio::buffer(handshake, (sizeof(handshake) - 1)), ec);
    	print_alerts(ses1, "ses1", true, true, true, &on_alert);
    	if (ec)
    	{
    		fprintf(stderr, "failed to write bittorrent handshake: %s\n"
    			, ec.message().c_str());
    		return false;
    	}

    	char buf[68];
    	fprintf(stderr, "read bittorrent handshake\n");
    	boost::asio::read(ssl_sock, boost::asio::buffer(buf, sizeof(buf)), ec);
    	print_alerts(ses1, "ses1", true, true, true, &on_alert);
    	if (ec)
    	{
    		fprintf(stderr, "failed to read bittorrent handshake: %s\n"
    			, ec.message().c_str());
    		return false;
    	}

    	if (memcmp(buf, "\x13" "BitTorrent protocol", 20) != 0)
    	{
    		fprintf(stderr, "invalid bittorrent handshake\n");
    		return false;

relevance 0 | ../test/test_timestamp_history.cpp:54 | test the case where we have > 120 samples (and have the base delay actually be updated)

## test the case where we have > 120 samples (and have the base delay actually be updated)

#### ../test/test_timestamp_history.cpp:54

relevance 0 | ../test/test_timestamp_history.cpp:55 | test the case where a sample is lower than the history entry but not lower than the base

## test the case where a sample is lower than the history entry but not lower than the base

#### ../test/test_timestamp_history.cpp:55

    #include "libtorrent/timestamp_history.hpp"

    TORRENT_TEST(timestamp_history)
    {
    	using namespace libtorrent;

    	timestamp_history h;
    	TEST_EQUAL(h.add_sample(0x32, false), 0);
    	TEST_EQUAL(h.base(), 0x32);
    	TEST_EQUAL(h.add_sample(0x33, false), 0x1);
    	TEST_EQUAL(h.base(), 0x32);
    	TEST_EQUAL(h.add_sample(0x3433, false), 0x3401);
    	TEST_EQUAL(h.base(), 0x32);
    	TEST_EQUAL(h.add_sample(0x30, false), 0);
    	TEST_EQUAL(h.base(), 0x30);

    	// test that wrapping of the timestamp is properly handled
    	h.add_sample(0xfffffff3, false);
    	TEST_EQUAL(h.base(), 0xfffffff3);

    }

relevance 0 | ../test/test_torrent_info.cpp:168 | test remap_files

## test remap_files

#### ../test/test_torrent_info.cpp:168

relevance 0 | ../test/test_torrent_info.cpp:169 | merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash"

## merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash"

#### ../test/test_torrent_info.cpp:169

relevance 0 | ../test/test_torrent_info.cpp:170 | torrent with 'p' (padfile) attribute

## torrent with 'p' (padfile) attribute

#### ../test/test_torrent_info.cpp:170

relevance 0 | ../test/test_torrent_info.cpp:171 | torrent with 'h' (hidden) attribute

## torrent with 'h' (hidden) attribute

#### ../test/test_torrent_info.cpp:171

relevance 0 | ../test/test_torrent_info.cpp:172 | torrent with 'x' (executable) attribute

## torrent with 'x' (executable) attribute

#### ../test/test_torrent_info.cpp:172

relevance 0 | ../test/test_torrent_info.cpp:173 | torrent with 'l' (symlink) attribute

## torrent with 'l' (symlink) attribute

#### ../test/test_torrent_info.cpp:173

relevance 0 | ../test/test_torrent_info.cpp:174 | creating a merkle torrent (torrent_info::build_merkle_list)

## creating a merkle torrent (torrent_info::build_merkle_list)

#### ../test/test_torrent_info.cpp:174

relevance 0 | ../test/test_torrent_info.cpp:175 | torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once)

## torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once)

#### ../test/test_torrent_info.cpp:175

relevance 0 | ../test/test_torrent_info.cpp:176 | torrents with a zero-length name

## torrents with a zero-length name

#### ../test/test_torrent_info.cpp:176

relevance 0 | ../test/test_torrent_info.cpp:177 | torrents with a merkle tree and add_merkle_nodes

## torrents with a merkle tree and add_merkle_nodes

#### ../test/test_torrent_info.cpp:177

relevance 0 | ../test/test_torrent_info.cpp:178 | torrent with a non-dictionary info-section

## torrent with a non-dictionary info-section

#### ../test/test_torrent_info.cpp:178

relevance 0 | ../test/test_torrent_info.cpp:179 | torrents with DHT nodes

## torrents with DHT nodes

#### ../test/test_torrent_info.cpp:179

relevance 0 | ../test/test_torrent_info.cpp:180 | torrent with url-list as a single string

## torrent with url-list as a single string

#### ../test/test_torrent_info.cpp:180

relevance 0 | ../test/test_torrent_info.cpp:181 | torrent with http seed as a single string

## torrent with http seed as a single string

#### ../test/test_torrent_info.cpp:181

relevance 0 | ../test/test_torrent_info.cpp:182 | torrent with a comment

## torrent with a comment

#### ../test/test_torrent_info.cpp:182

relevance 0 | ../test/test_torrent_info.cpp:183 | torrent with an SSL cert

## torrent with an SSL cert

#### ../test/test_torrent_info.cpp:183

relevance 0 | ../test/test_torrent_info.cpp:184 | torrent with attributes (executable and hidden)

## torrent with attributes (executable and hidden)

#### ../test/test_torrent_info.cpp:184

relevance 0 | ../test/test_torrent_info.cpp:185 | torrent_info::add_tracker

## torrent_info::add_tracker

#### ../test/test_torrent_info.cpp:185

relevance 0 | ../test/test_torrent_info.cpp:186 | torrent_info::unload

## torrent_info::unload

#### ../test/test_torrent_info.cpp:186

relevance 0 | ../test/test_torrent_info.cpp:187 | torrent_info constructor that takes an invalid bencoded buffer

## torrent_info constructor that takes an invalid bencoded buffer

#### ../test/test_torrent_info.cpp:187

relevance 0 | ../test/test_torrent_info.cpp:188 | verify_encoding with a string that triggers character replacement

## verify_encoding with a string that triggers character replacement

#### ../test/test_torrent_info.cpp:188

    {
    	{ "missing_piece_len.torrent", errors::torrent_missing_piece_length },
    	{ "invalid_piece_len.torrent", errors::torrent_missing_piece_length },
    	{ "negative_piece_len.torrent", errors::torrent_missing_piece_length },
    	{ "no_name.torrent", errors::torrent_missing_name },
    	{ "invalid_name.torrent", errors::torrent_missing_name },
    	{ "invalid_info.torrent", errors::torrent_missing_info },
    	{ "string.torrent", errors::torrent_is_no_dict },
    	{ "negative_size.torrent", errors::torrent_invalid_length },
    	{ "negative_file_size.torrent", errors::torrent_invalid_length },
    	{ "invalid_path_list.torrent", errors::torrent_invalid_name},
    	{ "missing_path_list.torrent", errors::torrent_missing_name },
    	{ "invalid_pieces.torrent", errors::torrent_missing_pieces },
    	{ "unaligned_pieces.torrent", errors::torrent_invalid_hashes },
    	{ "invalid_root_hash.torrent", errors::torrent_invalid_hashes },
    	{ "invalid_root_hash2.torrent", errors::torrent_missing_pieces },
    	{ "invalid_file_size.torrent", errors::torrent_invalid_length },
    	{ "invalid_symlink.torrent", errors::torrent_invalid_name },
    };

    TORRENT_TEST(add_url_seed)
    {
    	torrent_info ti(sha1_hash("                   "));
    	TEST_EQUAL(ti.web_seeds().size(), 0);

    	ti.add_url_seed("http://test.com");

    	TEST_EQUAL(ti.web_seeds().size(), 1);
    	web_seed_entry we = ti.web_seeds()[0];
    	TEST_EQUAL(we.type, web_seed_entry::url_seed);
    	TEST_EQUAL(we.url, "http://test.com");
    }

    TORRENT_TEST(add_http_seed)
    {
    	torrent_info ti(sha1_hash("                   "));
    	TEST_EQUAL(ti.web_seeds().size(), 0);

    	ti.add_http_seed("http://test.com");

    	TEST_EQUAL(ti.web_seeds().size(), 1);
    	web_seed_entry we = ti.web_seeds()[0];
    	TEST_EQUAL(we.type, web_seed_entry::http_seed);
    	TEST_EQUAL(we.url, "http://test.com");
    }

    TORRENT_TEST(set_web_seeds)
    {
    	torrent_info ti(sha1_hash("                   "));
    	TEST_EQUAL(ti.web_seeds().size(), 0);

relevance 0 | ../test/test_tracker.cpp:53 | test scrape requests

## test scrape requests

#### ../test/test_tracker.cpp:53

relevance 0 | ../test/test_tracker.cpp:54 | test parse peers6

## test parse peers6

#### ../test/test_tracker.cpp:54

relevance 0 | ../test/test_tracker.cpp:55 | test parse tracker-id

## test parse tracker-id

#### ../test/test_tracker.cpp:55

relevance 0 | ../test/test_tracker.cpp:56 | test parse failure-reason

## test parse failure-reason

#### ../test/test_tracker.cpp:56

relevance 0 | ../test/test_tracker.cpp:57 | test all failure paths, including invalid bencoding not a dictionary no files entry in scrape response no info-hash entry in scrape response malformed peers in peer list of dictionaries uneven number of bytes in peers and peers6 string responses

## test all failure paths, including invalid bencoding not a dictionary no files entry in scrape response no info-hash entry in scrape response malformed peers in peer list of dictionaries uneven number of bytes in peers and peers6 string responses

#### ../test/test_tracker.cpp:57

    #include "test.hpp"
    #include "setup_transfer.hpp"
    #include "udp_tracker.hpp"
    #include "settings.hpp"
    #include "libtorrent/alert.hpp"
    #include "libtorrent/peer_info.hpp" // for peer_list_entry
    #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6
    #include "libtorrent/alert_types.hpp"
    #include "libtorrent/session.hpp"
    #include "libtorrent/error_code.hpp"
    #include "libtorrent/tracker_manager.hpp"
    #include "libtorrent/http_tracker_connection.hpp" // for parse_tracker_response
    #include "libtorrent/torrent_info.hpp"
    #include "libtorrent/announce_entry.hpp"

    #include <fstream>

    using namespace libtorrent;
    namespace lt = libtorrent;

    TORRENT_TEST(parse_hostname_peers)
    {
    	char const response[] = "d5:peersld7:peer id20:aaaaaaaaaaaaaaaaaaaa2:ip13:test_hostname4:porti1000eed7:peer id20:bbbbabaababababababa2:ip12:another_host4:porti1001eeee";
    	error_code ec;
    	tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
    		, ec, false, sha1_hash());

    	TEST_EQUAL(ec, error_code());
    	TEST_EQUAL(resp.peers.size(), 2);
    	if (resp.peers.size() == 2)
    	{
    		peer_entry const& e0 = resp.peers[0];
    		peer_entry const& e1 = resp.peers[1];
    		TEST_EQUAL(e0.hostname, "test_hostname");
    		TEST_EQUAL(e0.port, 1000);
    		TEST_EQUAL(e0.pid, peer_id("aaaaaaaaaaaaaaaaaaaa"));

    		TEST_EQUAL(e1.hostname, "another_host");
    		TEST_EQUAL(e1.port, 1001);
    		TEST_EQUAL(e1.pid, peer_id("bbbbabaababababababa"));
    	}
    }

    TORRENT_TEST(parse_peers4)
    {
    	char const response[] = "d5:peers12:\x01\x02\x03\x04\x30\x10"
    		"\x09\x08\x07\x06\x20\x10" "e";
    	error_code ec;
    	tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
    		, ec, false, sha1_hash());

relevance 0 | ../test/test_transfer.cpp:211 | these settings_pack tests belong in their own test

## these settings_pack tests belong in their own test

#### ../test/test_transfer.cpp:211

    	pack.set_int(settings_pack::min_reconnect_time, 0);
    	pack.set_int(settings_pack::stop_tracker_timeout, 1);
    	pack.set_bool(settings_pack::announce_to_all_trackers, true);
    	pack.set_bool(settings_pack::announce_to_all_tiers, true);

    	// make sure we announce to both http and udp trackers
    	pack.set_bool(settings_pack::prefer_udp_trackers, false);
    	pack.set_bool(settings_pack::enable_outgoing_utp, false);
    	pack.set_bool(settings_pack::enable_incoming_utp, false);
    	pack.set_bool(settings_pack::enable_lsd, false);
    	pack.set_bool(settings_pack::enable_natpmp, false);
    	pack.set_bool(settings_pack::enable_upnp, false);
    	pack.set_bool(settings_pack::enable_dht, false);
    	pack.set_int(settings_pack::alert_mask, mask);

    	pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled);
    	pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled);

    	pack.set_bool(settings_pack::allow_multiple_connections_per_ip, false);

    	pack.set_int(settings_pack::unchoke_slots_limit, 0);
    	ses1.apply_settings(pack);
    	TEST_CHECK(ses1.get_settings().get_int(settings_pack::unchoke_slots_limit) == 0);

    	pack.set_int(settings_pack::unchoke_slots_limit, -1);
    	ses1.apply_settings(pack);
    	TEST_CHECK(ses1.get_settings().get_int(settings_pack::unchoke_slots_limit) == -1);

    	pack.set_int(settings_pack::unchoke_slots_limit, 8);
    	ses1.apply_settings(pack);
    	TEST_CHECK(ses1.get_settings().get_int(settings_pack::unchoke_slots_limit) == 8);

    	ses2.apply_settings(pack);

    	torrent_handle tor1;
    	torrent_handle tor2;

    	create_directory("tmp1_transfer", ec);
    	std::ofstream file("tmp1_transfer/temporary");
    	boost::shared_ptr<torrent_info> t = ::create_torrent(&file, "temporary", 32 * 1024, 13, false);
    	file.close();

    	TEST_CHECK(exists(combine_path("tmp1_transfer", "temporary")));

    	add_torrent_params addp(&test_storage_constructor);
    	addp.flags &= ~add_torrent_params::flag_paused;
    	addp.flags &= ~add_torrent_params::flag_auto_managed;

    	add_torrent_params params;
    	params.storage_mode = storage_mode;
    	params.flags &= ~add_torrent_params::flag_paused;

relevance 0 | ../test/test_transfer.cpp:290 | factor out the disk-full test into its own unit test

## factor out the disk-full test into its own unit test

#### ../test/test_transfer.cpp:290

    		print_alerts(ses1, "ses1", true, true, true, &on_alert);
    		print_alerts(ses2, "ses2", true, true, true, &on_alert);

    		if (i % 10 == 0)
    		{
    			print_ses_rate(i / 10.f, &st1, &st2);
    		}

    		if (!test_move_storage && st2.progress > 0.25f)
    		{
    			test_move_storage = true;
    			tor1.move_storage("tmp1_transfer_moved");
    			tor2.move_storage("tmp2_transfer_moved");
    			std::cerr << "moving storage" << std::endl;
    		}

    		// wait 10 loops before we restart the torrent. This lets
    		// us catch all events that failed (and would put the torrent
    		// back into upload mode) before we restart it.

    		if (test_disk_full && st2.upload_mode && ++upload_mode_timer > 10)
    		{
    			test_disk_full = false;
    			((test_storage*)tor2.get_storage_impl())->set_limit(16 * 1024 * 1024);

    			// if we reset the upload mode too soon, there may be more disk
    			// jobs failing right after, putting us back in upload mode. So,
    			// give the disk some time to fail all disk jobs before resetting
    			// upload mode to false
    			test_sleep(500);

    			// then we need to drain the alert queue, so the peer_disconnects
    			// counter doesn't get incremented by old alerts
    			print_alerts(ses1, "ses1", true, true, true, &on_alert);
    			print_alerts(ses2, "ses2", true, true, true, &on_alert);

    			lt::error_code err = tor2.status().errc;
    			fprintf(stderr, "error: \"%s\"\n", err.message().c_str());
    			TEST_CHECK(!err);
    			tor2.set_upload_mode(false);

    			// at this point we probably disconnected the seed
    			// so we need to reconnect as well
    			fprintf(stderr, "%s: reconnecting peer\n", time_now_string());
    			error_code ec;
    			tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec)
    				, ses1.listen_port()));

    			TEST_CHECK(tor2.status().is_finished == false);
    			fprintf(stderr, "disconnects: %d\n", peer_disconnects);
    			TEST_CHECK(peer_disconnects >= 2);

relevance 0 | ../test/test_upnp.cpp:109 | store the log and verify that some key messages are there

## store the log and verify that some key messages are there

#### ../test/test_upnp.cpp:109

    		"USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice\r\n"
    		"Location: http://127.0.0.1:%d/upnp.xml\r\n"
    		"Server: Custom/1.0 UPnP/1.0 Proc/Ver\r\n"
    		"EXT:\r\n"
    		"Cache-Control:max-age=180\r\n"
    		"DATE: Fri, 02 Jan 1970 08:10:38 GMT\r\n\r\n";

    	TORRENT_ASSERT(g_port != 0);
    	char buf[sizeof(msg) + 30];
    	int len = snprintf(buf, sizeof(buf), msg, g_port);

    	error_code ec;
    	sock->send(buf, len, ec);

    	if (ec) std::cerr << "*** error sending " << ec.message() << std::endl;
    }

    void log_callback(char const* err)
    {
    	std::cerr << "UPnP: " << err << std::endl;
    }

    struct callback_info
    {
    	int mapping;
    	int port;
    	error_code ec;
    	bool operator==(callback_info const& e)
    	{ return mapping == e.mapping && port == e.port && !ec == !e.ec; }
    };

    std::list<callback_info> callbacks;

    void callback(int mapping, address const& ip, int port, int protocol, error_code const& err)
    {
    	callback_info info = {mapping, port, err};
    	callbacks.push_back(info);
    	std::cerr << "mapping: " << mapping << ", port: " << port << ", IP: " << ip
    		<< ", proto: " << protocol << ", error: \"" << err.message() << "\"\n";
    }

    void run_upnp_test(char const* root_filename, char const* router_model, char const* control_name, int igd_version)
    {
    	libtorrent::io_service ios;

    	g_port = start_web_server();

    	std::vector<char> buf;
    	error_code ec;
    	load_file(root_filename, buf, ec);
    	buf.push_back(0);

relevance 0 | ../src/block_cache.cpp:1033 | it's somewhat expensive to iterate over this linked list. Presumably because of the random access of memory. It would be nice if pieces with no evictable blocks weren't in this list

## it's somewhat expensive to iterate over this linked list. Presumably because of the random access of memory. It would be nice if pieces with no evictable blocks weren't in this list

#### ../src/block_cache.cpp:1033

    	}
    	else if (m_last_cache_op == ghost_hit_lru1)
    	{
    		// when we insert new items or move things from L1 to L2
    		// evict blocks from L2
    		lru_list[1] = &m_lru[cached_piece_entry::read_lru2];
    		lru_list[2] = &m_lru[cached_piece_entry::read_lru1];
    	}
    	else
    	{
    		// when we get cache hits in L2 evict from L1
    		lru_list[1] = &m_lru[cached_piece_entry::read_lru1];
    		lru_list[2] = &m_lru[cached_piece_entry::read_lru2];
    	}

    	// end refers to which end of the ARC cache we're evicting
    	// from. The LFU or the LRU end
    	for (int end = 0; num > 0 && end < 3; ++end)
    	{
    		// iterate over all blocks in order of last being used (oldest first) and
    		for (list_iterator<cached_piece_entry> i = lru_list[end]->iterate(); i.get() && num > 0;)
    		{
    			cached_piece_entry* pe = i.get();
    			TORRENT_PIECE_ASSERT(pe->in_use, pe);
    			i.next();

    			if (pe == ignore)
    				continue;

    			if (pe->ok_to_evict() && pe->num_blocks == 0)
    			{
    #ifdef TORRENT_DEBUG
    				for (int j = 0; j < pe->blocks_in_piece; ++j)
    					TORRENT_PIECE_ASSERT(pe->blocks[j].buf == 0, pe);
    #endif
    				TORRENT_PIECE_ASSERT(pe->refcount == 0, pe);
    				move_to_ghost(pe);
    				continue;
    			}

    			TORRENT_PIECE_ASSERT(pe->num_dirty == 0, pe);

    			// all blocks are pinned in this piece, skip it
    			if (pe->num_blocks <= pe->pinned) continue;

    			// go through the blocks and evict the ones that are not dirty and not
    			// referenced
    			int removed = 0;
    			for (int j = 0; j < pe->blocks_in_piece && num > 0; ++j)
    			{
    				cached_block_entry& b = pe->blocks[j];

relevance 0 | ../src/block_cache.cpp:1104 | this should probably only be done every n:th time

## this should probably only be done every n:th time

#### ../src/block_cache.cpp:1104

    			}

    			if (pe->ok_to_evict() && pe->num_blocks == 0)
    			{
    #ifdef TORRENT_DEBUG
    				for (int j = 0; j < pe->blocks_in_piece; ++j)
    					TORRENT_PIECE_ASSERT(pe->blocks[j].buf == 0, pe);
    #endif
    				move_to_ghost(pe);
    			}
    		}
    	}

    	// if we can't evict enough blocks from the read cache, also look at write
    	// cache pieces for blocks that have already been written to disk and can be
    	// evicted the first pass, we only evict blocks that have been hashed, the
    	// second pass we flush anything this is potentially a very expensive
    	// operation, since we're likely to have iterate every single block in the
    	// cache, and we might not get to evict anything.

    	if (num > 0 && m_read_cache_size > m_pinned_blocks)
    	{
    		for (int pass = 0; pass < 2 && num > 0; ++pass)
    		{
    			for (list_iterator<cached_piece_entry> i = m_lru[cached_piece_entry::write_lru].iterate(); i.get() && num > 0;)
    			{
    				cached_piece_entry* pe = i.get();
    				TORRENT_PIECE_ASSERT(pe->in_use, pe);

    				i.next();

    				if (pe == ignore)
    					continue;

    				if (pe->ok_to_evict() && pe->num_blocks == 0)
    				{
    #ifdef TORRENT_DEBUG
    					for (int j = 0; j < pe->blocks_in_piece; ++j)
    						TORRENT_PIECE_ASSERT(pe->blocks[j].buf == 0, pe);
    #endif
    					TORRENT_PIECE_ASSERT(pe->refcount == 0, pe);
    					erase_piece(pe);
    					continue;
    				}

    				// all blocks in this piece are dirty
    				if (pe->num_dirty == pe->num_blocks)
    					continue;

    				int end = pe->blocks_in_piece;

relevance 0 | ../src/block_cache.cpp:1797 | create a holder for refcounts that automatically decrement

## create a holder for refcounts that automatically decrement

#### ../src/block_cache.cpp:1797

    	}

    	j->buffer.disk_block = allocate_buffer("send buffer");
    	if (j->buffer.disk_block == 0) return -2;

    	while (size > 0)
    	{
    		TORRENT_PIECE_ASSERT(pe->blocks[block].buf, pe);
    		int to_copy = (std::min)(block_size()
    			- block_offset, size);
    		std::memcpy(j->buffer.disk_block + buffer_offset
    			, pe->blocks[block].buf + block_offset
    			, to_copy);
    		size -= to_copy;
    		block_offset = 0;
    		buffer_offset += to_copy;
    		++block;
    	}
    	// we incremented the refcount for both of these blocks.
    	// now decrement it.
    	dec_block_refcount(pe, start_block, ref_reading);
    	if (blocks_to_read == 2) dec_block_refcount(pe, start_block + 1, ref_reading);
    	maybe_free_piece(pe);
    	return j->d.io.buffer_size;
    }

    void block_cache::reclaim_block(block_cache_reference const& ref)
    {
    	cached_piece_entry* pe = find_piece(ref);
    	TORRENT_ASSERT(pe);
    	if (pe == NULL) return;

    	TORRENT_PIECE_ASSERT(pe->in_use, pe);

    	TORRENT_PIECE_ASSERT(pe->blocks[ref.block].buf, pe);
    	dec_block_refcount(pe, ref.block, block_cache::ref_reading);

    	TORRENT_PIECE_ASSERT(m_send_buffer_blocks > 0, pe);
    	--m_send_buffer_blocks;

    	maybe_free_piece(pe);
    }

    bool block_cache::maybe_free_piece(cached_piece_entry* pe)
    {
    	if (!pe->ok_to_evict()
    		|| !pe->marked_for_eviction
    		|| !pe->jobs.empty())
    		return false;

    	DLOG(stderr, "[%p] block_cache maybe_free_piece "

relevance 0 | ../src/bt_peer_connection.cpp:700 | this could be optimized using knuth morris pratt

## this could be optimized using knuth morris pratt

#### ../src/bt_peer_connection.cpp:700

    		}

    		m_rc4->set_incoming_key(&remote_key[0], 20);
    		m_rc4->set_outgoing_key(&local_key[0], 20);

    #ifndef TORRENT_DISABLE_LOGGING
    		peer_log(peer_log_alert::info, "ENCRYPTION", "computed RC4 keys");
    #endif
    	}

    	int bt_peer_connection::get_syncoffset(char const* src, int src_size,
    		char const* target, int target_size) const
    	{
    		TORRENT_ASSERT(target_size >= src_size);
    		TORRENT_ASSERT(src_size > 0);
    		TORRENT_ASSERT(src);
    		TORRENT_ASSERT(target);

    		int traverse_limit = target_size - src_size;

    		for (int i = 0; i < traverse_limit; ++i)
    		{
    			char const* target_ptr = target + i;
    			if (std::equal(src, src+src_size, target_ptr))
    				return i;
    		}

    		// Partial sync
    //		for (int i = 0; i < target_size; ++i)
    //		{
    //			// first is iterator in src[] at which mismatch occurs
    //			// second is iterator in target[] at which mismatch occurs
    //			std::pair<const char*, const char*> ret;
    //			int src_sync_size;
    //			if (i > traverse_limit) // partial sync test
    //			{
    //				ret = std::mismatch(src, src + src_size - (i - traverse_limit), &target[i]);
    //				src_sync_size = ret.first - src;
    //				if (src_sync_size == (src_size - (i - traverse_limit)))
    //					return i;
    //			}
    //			else // complete sync test
    //			{
    //				ret = std::mismatch(src, src + src_size, &target[i]);
    //				src_sync_size = ret.first - src;
    //				if (src_sync_size == src_size)
    //					return i;
    //			}
    //		}

    		// no complete sync

relevance 0 | ../src/bt_peer_connection.cpp:2254 | if we're finished, send upload_only message

## if we're finished, send upload_only message

#### ../src/bt_peer_connection.cpp:2254

    		}
    		peer_log(peer_log_alert::outgoing_message, "BITFIELD"
    			, "%s", bitfield_string.c_str());
    #endif
    		m_sent_bitfield = true;

    		send_buffer(reinterpret_cast<char const*>(msg), packet_size);

    		stats_counters().inc_stats_counter(counters::num_outgoing_bitfield);

    		if (num_lazy_pieces > 0)
    		{
    			for (int i = 0; i < num_lazy_pieces; ++i)
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				peer_log(peer_log_alert::outgoing_message, "HAVE"
    					, "piece: %d", lazy_pieces[i]);
    #endif
    				write_have(lazy_pieces[i]);
    			}
    		}
    	}

    #ifndef TORRENT_DISABLE_EXTENSIONS
    	void bt_peer_connection::write_extensions()
    	{
    		INVARIANT_CHECK;

    		TORRENT_ASSERT(m_supports_extensions);
    		TORRENT_ASSERT(m_sent_handshake);

    		entry handshake;
    		entry::dictionary_type& m = handshake["m"].dict();

    		// if we're using a proxy, our listen port won't be useful
    		// anyway.
    		if (!m_settings.get_bool(settings_pack::force_proxy) && is_outgoing())
    			handshake["p"] = m_ses.listen_port();

    		// only send the port in case we bade the connection
    		// on incoming connections the other end already knows
    		// our listen port
    		if (!m_settings.get_bool(settings_pack::anonymous_mode))
    		{
    			handshake["v"] = m_settings.get_str(settings_pack::handshake_client_version).empty()
    				? m_settings.get_str(settings_pack::user_agent)
    				: m_settings.get_str(settings_pack::handshake_client_version);
    		}

    		std::string remote_address;
    		std::back_insert_iterator<std::string> out(remote_address);

relevance 0 | ../src/choker.cpp:353 | optimize this using partial_sort or something. We don't need to sort the entire list

## optimize this using partial_sort or something. We don't need to sort the entire list

#### ../src/choker.cpp:353

    			return upload_slots;
    		}

    		// ==== rate-based ====
    		//
    		// The rate based unchoker looks at our upload rate to peers, and find
    		// a balance between number of upload slots and the rate we achieve. The
    		// intention is to not spread upload bandwidth too thin, but also to not
    		// unchoke few enough peers to not be able to saturate the up-link.
    		// this is done by traversing the peers sorted by our upload rate to
    		// them in decreasing rates. For each peer we increase our threshold
    		// by 1 kB/s. The first peer we get to to whom we upload slower than
    		// the threshold, we stop and that's the number of unchoke slots we have.
    		if (sett.get_int(settings_pack::choking_algorithm)
    			== settings_pack::rate_based_choker)
    		{
    			// first reset the number of unchoke slots, because we'll calculate
    			// it purely based on the current state of our peers.
    			upload_slots = 0;

relevance 0 | ../src/choker.cpp:356 | make the comparison function a free function and move it into this cpp file

## make the comparison function a free function and move it into this cpp file

#### ../src/choker.cpp:356

    		}

    		// ==== rate-based ====
    		//
    		// The rate based unchoker looks at our upload rate to peers, and find
    		// a balance between number of upload slots and the rate we achieve. The
    		// intention is to not spread upload bandwidth too thin, but also to not
    		// unchoke few enough peers to not be able to saturate the up-link.
    		// this is done by traversing the peers sorted by our upload rate to
    		// them in decreasing rates. For each peer we increase our threshold
    		// by 1 kB/s. The first peer we get to to whom we upload slower than
    		// the threshold, we stop and that's the number of unchoke slots we have.
    		if (sett.get_int(settings_pack::choking_algorithm)
    			== settings_pack::rate_based_choker)
    		{
    			// first reset the number of unchoke slots, because we'll calculate
    			// it purely based on the current state of our peers.
    			upload_slots = 0;

    			std::sort(peers.begin(), peers.end()
    				, boost::bind(&upload_rate_compare, _1, _2));

relevance 0 | ../src/choker.cpp:361 | make configurable

## make configurable

#### ../src/choker.cpp:361

    		//
    		// The rate based unchoker looks at our upload rate to peers, and find
    		// a balance between number of upload slots and the rate we achieve. The
    		// intention is to not spread upload bandwidth too thin, but also to not
    		// unchoke few enough peers to not be able to saturate the up-link.
    		// this is done by traversing the peers sorted by our upload rate to
    		// them in decreasing rates. For each peer we increase our threshold
    		// by 1 kB/s. The first peer we get to to whom we upload slower than
    		// the threshold, we stop and that's the number of unchoke slots we have.
    		if (sett.get_int(settings_pack::choking_algorithm)
    			== settings_pack::rate_based_choker)
    		{
    			// first reset the number of unchoke slots, because we'll calculate
    			// it purely based on the current state of our peers.
    			upload_slots = 0;

    			std::sort(peers.begin(), peers.end()
    				, boost::bind(&upload_rate_compare, _1, _2));

    			int rate_threshold = 1024;

    			for (std::vector<peer_connection*>::const_iterator i = peers.begin()
    				, end(peers.end()); i != end; ++i)
    			{
    				peer_connection const& p = **i;
    				int const rate = int(p.uploaded_in_last_round()
    					* 1000 / total_milliseconds(unchoke_interval));

    				if (rate < rate_threshold) break;

    				++upload_slots;

relevance 0 | ../src/choker.cpp:375 | make configurable

## make configurable

#### ../src/choker.cpp:375

    			// it purely based on the current state of our peers.
    			upload_slots = 0;

    			std::sort(peers.begin(), peers.end()
    				, boost::bind(&upload_rate_compare, _1, _2));

    			int rate_threshold = 1024;

    			for (std::vector<peer_connection*>::const_iterator i = peers.begin()
    				, end(peers.end()); i != end; ++i)
    			{
    				peer_connection const& p = **i;
    				int const rate = int(p.uploaded_in_last_round()
    					* 1000 / total_milliseconds(unchoke_interval));

    				if (rate < rate_threshold) break;

    				++upload_slots;

    				rate_threshold += 1024;
    			}
    			++upload_slots;
    		}

    		// sorts the peers that are eligible for unchoke by download rate and
    		// secondary by total upload. The reason for this is, if all torrents are
    		// being seeded, the download rate will be 0, and the peers we have sent
    		// the least to should be unchoked

    		// we use partial sort here, because we only care about the top
    		// upload_slots peers.

    		if (sett.get_int(settings_pack::seed_choking_algorithm)
    			== settings_pack::round_robin)
    		{
    			int const pieces = sett.get_int(settings_pack::seeding_piece_quota);

    			std::partial_sort(peers.begin(), peers.begin()
    				+ (std::min)(upload_slots, int(peers.size())), peers.end()
    				, boost::bind(&unchoke_compare_rr, _1, _2, pieces));
    		}
    		else if (sett.get_int(settings_pack::seed_choking_algorithm)
    			== settings_pack::fastest_upload)
    		{
    			std::partial_sort(peers.begin(), peers.begin()
    				+ (std::min)(upload_slots, int(peers.size())), peers.end()
    				, boost::bind(&unchoke_compare_fastest_upload, _1, _2));
    		}
    		else if (sett.get_int(settings_pack::seed_choking_algorithm)
    			== settings_pack::anti_leech)

relevance 0 | ../src/create_torrent.cpp:294 | this should probably be optional

## this should probably be optional

#### ../src/create_torrent.cpp:294

    		counters cnt;
    		disk_io_thread disk_thread(ios, cnt, 0);
    		disk_thread.set_num_threads(1);

    		storage_params params;
    		params.files = &t.files();
    		params.mapped_files = NULL;
    		params.path = path;
    		params.pool = &disk_thread.files();
    		params.mode = storage_mode_sparse;

    		storage_interface* storage_impl = default_storage_constructor(params);

    		boost::shared_ptr<piece_manager> storage = boost::make_shared<piece_manager>(
    			storage_impl, dummy, const_cast<file_storage*>(&t.files()));

    		settings_pack sett;
    		sett.set_int(settings_pack::cache_size, 0);
    		sett.set_int(settings_pack::aio_threads, 2);

    		alert_manager dummy2(0, 0);
    		disk_thread.set_settings(&sett, dummy2);

    		int piece_counter = 0;
    		int completed_piece = 0;
    		int piece_read_ahead = 15 * 1024 * 1024 / t.piece_length();
    		if (piece_read_ahead < 1) piece_read_ahead = 1;

    		for (int i = 0; i < piece_read_ahead; ++i)
    		{
    			disk_thread.async_hash(storage.get(), i, disk_io_job::sequential_access
    				, boost::bind(&on_hash, _1, &t, storage, &disk_thread
    				, &piece_counter, &completed_piece, &f, &ec), NULL);
    			++piece_counter;
    			if (piece_counter >= t.num_pieces()) break;
    		}
    		disk_thread.submit_jobs();
    		ios.run(ec);
    	}

    	create_torrent::~create_torrent() {}

    	create_torrent::create_torrent(file_storage& fs, int piece_size
    		, int pad_file_limit, int flags, int alignment)
    		: m_files(fs)
    		, m_creation_date(time(0))
    		, m_multifile(fs.num_files() > 1)
    		, m_private(false)
    		, m_merkle_torrent((flags & merkle) != 0)
    		, m_include_mtime((flags & modification_time) != 0)
    		, m_include_symlinks((flags & symlinks) != 0)

relevance 0 | ../src/disk_buffer_pool.cpp:257 | perhaps we should sort the buffers here?

## perhaps we should sort the buffers here?

#### ../src/disk_buffer_pool.cpp:257

    		mutex::scoped_lock l(m_pool_mutex);
    		for (int i = 0; i < iov_len; ++i)
    		{
    			iov[i].iov_base = allocate_buffer_impl(l, "pending read");
    			iov[i].iov_len = block_size();
    			if (iov[i].iov_base == NULL)
    			{
    				// uh oh. We failed to allocate the buffer!
    				// we need to roll back and free all the buffers
    				// we've already allocated
    				for (int j = 0; j < i; ++j)
    					free_buffer_impl(static_cast<char*>(iov[j].iov_base), l);
    				return -1;
    			}
    		}
    		return 0;
    	}

    	void disk_buffer_pool::free_iovec(file::iovec_t* iov, int iov_len)
    	{
    		mutex::scoped_lock l(m_pool_mutex);
    		for (int i = 0; i < iov_len; ++i)
    			free_buffer_impl(static_cast<char*>(iov[i].iov_base), l);
    		check_buffer_level(l);
    	}

    	char* disk_buffer_pool::allocate_buffer_impl(mutex::scoped_lock& l
    		, char const*)
    	{
    		TORRENT_ASSERT(m_settings_set);
    		TORRENT_ASSERT(m_magic == 0x1337);
    		TORRENT_ASSERT(l.locked());
    		TORRENT_UNUSED(l);

    		char* ret;
    #if TORRENT_HAVE_MMAP && !defined TORRENT_NO_DEPRECATE
    		if (m_cache_pool)
    		{
    			if (m_free_list.size() <= (m_max_use - m_low_watermark)
    				/ 2 && !m_exceeded_max_size)
    			{
    				m_exceeded_max_size = true;
    				m_trigger_cache_trim();
    			}
    			if (m_free_list.empty()) return 0;
    			boost::uint64_t slot_index = m_free_list.back();
    			m_free_list.pop_back();
    			ret = m_cache_pool + (slot_index * 0x4000);
    			TORRENT_ASSERT(is_disk_buffer(ret, l));
    		}
    		else

relevance 0 | ../src/disk_io_thread.cpp:872 | it would be nice to optimize this by having the cache pieces also ordered by

## it would be nice to optimize this by having the cache pieces also ordered by

#### ../src/disk_io_thread.cpp:872

    			// from disk_io_thread::do_delete, which is a fence job and should
    			// have any other jobs active, i.e. there should not be any references
    			// keeping pieces or blocks alive
    			if ((flags & flush_delete_cache) && (flags & flush_expect_clear))
    			{
    				boost::unordered_set<cached_piece_entry*> const& storage_pieces = storage->cached_pieces();
    				for (boost::unordered_set<cached_piece_entry*>::const_iterator i = storage_pieces.begin()
    					, end(storage_pieces.end()); i != end; ++i)
    				{
    					cached_piece_entry* pe = m_disk_cache.find_piece(storage, (*i)->piece);
    					TORRENT_PIECE_ASSERT(pe->num_dirty == 0, pe);
    				}
    			}
    #endif
    		}
    		else
    		{
    			std::pair<block_cache::iterator, block_cache::iterator> range = m_disk_cache.all_pieces();
    			while (range.first != range.second)
    			{
    				if ((flags & (flush_read_cache | flush_delete_cache)) == 0)
    				{
    					// if we're not flushing the read cache, and not deleting the
    					// cache, skip pieces with no dirty blocks, i.e. read cache
    					// pieces
    					while (range.first->num_dirty == 0)
    					{
    						++range.first;
    						if (range.first == range.second) return;
    					}
    				}
    				cached_piece_entry* pe = const_cast<cached_piece_entry*>(&*range.first);
    				flush_piece(pe, flags, completed_jobs, l);
    				range = m_disk_cache.all_pieces();
    			}
    		}
    	}

    	// this is called if we're exceeding (or about to exceed) the cache
    	// size limit. This means we should not restrict ourselves to contiguous
    	// blocks of write cache line size, but try to flush all old blocks
    	// this is why we pass in 1 as cont_block to the flushing functions
    	void disk_io_thread::try_flush_write_blocks(int num, jobqueue_t& completed_jobs
    		, mutex::scoped_lock& l)
    	{
    		DLOG("try_flush_write_blocks: %d\n", num);

    		list_iterator<cached_piece_entry> range = m_disk_cache.write_lru_pieces();
    		std::vector<std::pair<boost::shared_ptr<piece_manager>, int> > pieces;
    		pieces.reserve(m_disk_cache.num_write_lru_pieces());

relevance 0 | ../src/disk_io_thread.cpp:915 | instead of doing a lookup each time through the loop, save cached_piece_entry pointers with piece_refcount incremented to pin them

## instead of doing a lookup each time through the loop, save cached_piece_entry pointers with piece_refcount incremented to pin them

#### ../src/disk_io_thread.cpp:915

    	// this is why we pass in 1 as cont_block to the flushing functions
    	void disk_io_thread::try_flush_write_blocks(int num, jobqueue_t& completed_jobs
    		, mutex::scoped_lock& l)
    	{
    		DLOG("try_flush_write_blocks: %d\n", num);

    		list_iterator<cached_piece_entry> range = m_disk_cache.write_lru_pieces();
    		std::vector<std::pair<boost::shared_ptr<piece_manager>, int> > pieces;
    		pieces.reserve(m_disk_cache.num_write_lru_pieces());

    		for (list_iterator<cached_piece_entry> p = range; p.get() && num > 0; p.next())
    		{
    			cached_piece_entry* e = p.get();
    			if (e->num_dirty == 0) continue;
    			pieces.push_back(std::make_pair(e->storage, int(e->piece)));
    		}

    		for (std::vector<std::pair<boost::shared_ptr<piece_manager>, int> >::iterator i = pieces.begin()
    			, end(pieces.end()); i != end; ++i)
    		{
    			cached_piece_entry* pe = m_disk_cache.find_piece(i->first.get(), i->second);
    			if (pe == NULL) continue;

    			// another thread may flush this piece while we're looping and
    			// evict it into a read piece and then also evict it to ghost
    			if (pe->cache_state != cached_piece_entry::write_lru) continue;

    #if TORRENT_USE_ASSERTS
    			pe->piece_log.push_back(piece_log_t(piece_log_t::try_flush_write_blocks, -1));
    #endif
    			++pe->piece_refcount;
    			kick_hasher(pe, l);
    			num -= try_flush_hashed(pe, 1, completed_jobs, l);
    			--pe->piece_refcount;

    			m_disk_cache.maybe_free_piece(pe);
    		}

    		// when the write cache is under high pressure, it is likely
    		// counter productive to actually do this, since a piece may
    		// not have had its flush_hashed job run on it
    		// so only do it if no other thread is currently flushing

    		if (num == 0 || m_stats_counters[counters::num_writing_threads] > 0) return;

    		// if we still need to flush blocks, start over and flush
    		// everything in LRU order (degrade to lru cache eviction)
    		for (std::vector<std::pair<boost::shared_ptr<piece_manager>, int> >::iterator i = pieces.begin()
    			, end(pieces.end()); i != end; ++i)
    		{
    			cached_piece_entry* pe = m_disk_cache.find_piece(i->first.get(), i->second);

relevance 0 | ../src/disk_io_thread.cpp:1104 | instead of doing this. pass in the settings to each storage_interface call. Each disk thread could hold its most recent understanding of the settings in a shared_ptr, and update it every time it wakes up from a job. That way each access to the settings won't require a mutex to be held.

## instead of doing this. pass in the settings to each storage_interface call. Each disk thread could hold its most recent understanding of the settings in a shared_ptr, and update it every time it wakes up from a job. That way each access to the settings won't require a mutex to be held.

#### ../src/disk_io_thread.cpp:1104

    	{
    		INVARIANT_CHECK;
    		TORRENT_ASSERT(j->next == 0);
    		TORRENT_ASSERT((j->flags & disk_io_job::in_progress) || !j->storage);

    #if DEBUG_DISK_THREAD
    		{
    			mutex::scoped_lock l(m_cache_mutex);

    			DLOG("perform_job job: %s ( %s%s) piece: %d offset: %d outstanding: %d\n"
    				, job_action_name[j->action]
    				, (j->flags & disk_io_job::fence) ? "fence ": ""
    				, (j->flags & disk_io_job::force_copy) ? "force_copy ": ""
    				, j->piece, j->d.io.offset
    				, j->storage ? j->storage->num_outstanding_jobs() : -1);
    		}
    #endif

    		boost::shared_ptr<piece_manager> storage = j->storage;

    		if (storage && storage->get_storage_impl()->m_settings == 0)
    			storage->get_storage_impl()->m_settings = &m_settings;

    		TORRENT_ASSERT(j->action < sizeof(job_functions)/sizeof(job_functions[0]));

    		time_point start_time = clock_type::now();

    		m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, 1);

    		// call disk function
    		int ret = (this->*(job_functions[j->action]))(j, completed_jobs);

    		// note that -2 erros are OK
    		TORRENT_ASSERT(ret != -1 || (j->error.ec && j->error.operation != 0));

    		m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, -1);

    		mutex::scoped_lock l(m_cache_mutex);
    		if (m_cache_check_state == cache_check_idle)
    		{
    			m_cache_check_state = cache_check_active;
    			while (m_cache_check_state != cache_check_idle)
    			{
    				check_cache_level(l, completed_jobs);
    				TORRENT_ASSERT(l.locked());
    				--m_cache_check_state;
    			}
    		}
    		else
    		{
    			m_cache_check_state = cache_check_reinvoke;

relevance 0 | ../src/disk_io_thread.cpp:1149 | a potentially more efficient solution would be to have a special queue for retry jobs, that's only ever run when a job completes, in any thread. It would only work if counters::num_running_disk_jobs > 0

## a potentially more efficient solution would be to have a special queue for retry jobs, that's only ever run when a job completes, in any thread. It would only work if counters::num_running_disk_jobs > 0

#### ../src/disk_io_thread.cpp:1149

    			while (m_cache_check_state != cache_check_idle)
    			{
    				check_cache_level(l, completed_jobs);
    				TORRENT_ASSERT(l.locked());
    				--m_cache_check_state;
    			}
    		}
    		else
    		{
    			m_cache_check_state = cache_check_reinvoke;
    		}
    		l.unlock();

    		if (ret == retry_job)
    		{
    			mutex::scoped_lock l2(m_job_mutex);
    			// to avoid busy looping here, give up
    			// our quanta in case there aren't any other
    			// jobs to run in between

    			TORRENT_ASSERT((j->flags & disk_io_job::in_progress) || !j->storage);

    			bool need_sleep = m_queued_jobs.empty();
    			m_queued_jobs.push_back(j);
    			l2.unlock();
    			if (need_sleep) sleep(0);
    			return;
    		}

    		if (ret == defer_handler) return;

    		j->ret = ret;

    		time_point now = clock_type::now();
    		m_job_time.add_sample(total_microseconds(now - start_time));
    		completed_jobs.push_back(j);
    	}

    	int disk_io_thread::do_uncached_read(disk_io_job* j)
    	{
    		j->buffer.disk_block = m_disk_cache.allocate_buffer("send buffer");
    		if (j->buffer.disk_block == 0)
    		{
    			j->error.ec = error::no_memory;
    			j->error.operation = storage_error::alloc_cache_piece;
    			return -1;
    		}

    		time_point start_time = clock_type::now();

relevance 0 | ../src/disk_io_thread.cpp:1820 | maybe the tailqueue_iterator<disk_io_job> should contain a pointer-pointer instead and have an unlink function

## maybe the tailqueue_iterator<disk_io_job> should contain a pointer-pointer instead and have an unlink function

#### ../src/disk_io_thread.cpp:1820

    		add_fence_job(storage, j);
    	}

    	void disk_io_thread::async_delete_files(piece_manager* storage
    		, int const options
    		, boost::function<void(disk_io_job const*)> const& handler)
    	{
    #ifdef TORRENT_DEBUG
    		// the caller must increment the torrent refcount before
    		// issuing an async disk request
    		storage->assert_torrent_refcount();
    #endif

    		// remove cache blocks belonging to this torrent
    		jobqueue_t completed_jobs;

    		// remove outstanding jobs belonging to this torrent
    		mutex::scoped_lock l2(m_job_mutex);

    		disk_io_job* qj = m_queued_jobs.get_all();
    		jobqueue_t to_abort;

    		// if we encounter any read jobs in the queue, we need to clear the
    		// "outstanding_read" flag on its piece, as we abort the job
    		std::vector<std::pair<piece_manager*, int> > pieces;

    		while (qj)
    		{
    			disk_io_job* next = qj->next;
    #if TORRENT_USE_ASSERTS
    			qj->next = NULL;
    #endif
    			if (qj->action == disk_io_job::read)
    			{
    				pieces.push_back(std::make_pair(qj->storage.get(), int(qj->piece)));
    			}

    			if (qj->storage.get() == storage)
    				to_abort.push_back(qj);
    			else
    				m_queued_jobs.push_back(qj);
    			qj = next;
    		}
    		l2.unlock();

    		mutex::scoped_lock l(m_cache_mutex);
    		for (std::vector<std::pair<piece_manager*, int> >::iterator i = pieces.begin()
    			, end(pieces.end()); i != end; ++i)
    		{
    			cached_piece_entry* pe = m_disk_cache.find_piece(i->first, i->second);

relevance 0 | ../src/disk_io_thread.cpp:2104 | this is potentially very expensive. One way to solve it would be to have a fence for just this one piece.

## this is potentially very expensive. One way to solve it would be to have a fence for just this one piece.

#### ../src/disk_io_thread.cpp:2104

    	}

    	void disk_io_thread::async_clear_piece(piece_manager* storage, int index
    		, boost::function<void(disk_io_job const*)> const& handler)
    	{
    #ifdef TORRENT_DEBUG
    		// the caller must increment the torrent refcount before
    		// issuing an async disk request
    		storage->assert_torrent_refcount();
    #endif

    		disk_io_job* j = allocate_job(disk_io_job::clear_piece);
    		j->storage = storage->shared_from_this();
    		j->piece = index;
    		j->callback = handler;

    		// regular jobs are not guaranteed to be executed in-order
    		// since clear piece must guarantee that all write jobs that
    		// have been issued finish before the clear piece job completes

    		add_fence_job(storage, j);
    	}

    	void disk_io_thread::clear_piece(piece_manager* storage, int index)
    	{
    		mutex::scoped_lock l(m_cache_mutex);

    		cached_piece_entry* pe = m_disk_cache.find_piece(storage, index);
    		if (pe == 0) return;
    		TORRENT_PIECE_ASSERT(pe->hashing == false, pe);
    		pe->hashing_done = 0;
    		delete pe->hash;
    		pe->hash = NULL;

    		// evict_piece returns true if the piece was in fact
    		// evicted. A piece may fail to be evicted if there
    		// are still outstanding operations on it, which should
    		// never be the case when this function is used
    		// in fact, no jobs should really be hung on this piece
    		// at this point
    		jobqueue_t jobs;
    		bool ok = m_disk_cache.evict_piece(pe, jobs, block_cache::allow_ghost);
    		TORRENT_PIECE_ASSERT(ok, pe);
    		TORRENT_UNUSED(ok);
    		fail_jobs(storage_error(boost::asio::error::operation_aborted), jobs);
    	}

    	void disk_io_thread::kick_hasher(cached_piece_entry* pe, mutex::scoped_lock& l)
    	{
    		if (!pe->hash) return;
    		if (pe->hashing) return;

relevance 0 | ../src/disk_io_thread.cpp:2368 | we should probably just hang the job on the piece and make sure the hasher gets kicked

## we should probably just hang the job on the piece and make sure the hasher gets kicked

#### ../src/disk_io_thread.cpp:2368

    		if (pe == NULL)
    		{
    			int cache_state = (j->flags & disk_io_job::volatile_read)
    				? cached_piece_entry::volatile_read_lru
    				: cached_piece_entry::read_lru1;
    			pe = m_disk_cache.allocate_piece(j, cache_state);
    		}
    		if (pe == NULL)
    		{
    			j->error.ec = error::no_memory;
    			j->error.operation = storage_error::alloc_cache_piece;
    			return -1;
    		}

    		if (pe->hashing)
    		{
    			TORRENT_PIECE_ASSERT(pe->hash, pe);
    			// another thread is hashing this piece right now
    			// try again in a little bit
    			DLOG("do_hash: retry\n");
    			return retry_job;
    		}

    		pe->hashing = 1;

    		TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
    			|| pe->cache_state == cached_piece_entry::read_lru2, pe);
    		++pe->piece_refcount;

    		if (pe->hash == NULL)
    		{
    			pe->hashing_done = 0;
    			pe->hash = new partial_hash;
    		}
    		partial_hash* ph = pe->hash;

    		int block_size = m_disk_cache.block_size();
    		int blocks_in_piece = (piece_size + block_size - 1) / block_size;

    		// keep track of which blocks we have locked by incrementing
    		// their refcounts. This is used to decrement only these blocks
    		// later.
    		int* locked_blocks = TORRENT_ALLOCA(int, blocks_in_piece);
    		memset(locked_blocks, 0, blocks_in_piece * sizeof(int));
    		int num_locked_blocks = 0;

    		// increment the refcounts of all
    		// blocks up front, and then hash them without holding the lock
    		TORRENT_PIECE_ASSERT(ph->offset % block_size == 0, pe);
    		for (int i = ph->offset / block_size; i < blocks_in_piece; ++i)
    		{

relevance 0 | ../src/disk_io_thread.cpp:2444 | introduce a holder class that automatically increments and decrements the piece_refcount

## introduce a holder class that automatically increments and decrements the piece_refcount

#### ../src/disk_io_thread.cpp:2444

    		{
    			file::iovec_t iov;
    			iov.iov_len = (std::min)(block_size, piece_size - offset);

    			if (next_locked_block < num_locked_blocks
    				&& locked_blocks[next_locked_block] == i)
    			{
    				++next_locked_block;
    				TORRENT_PIECE_ASSERT(pe->blocks[i].buf, pe);
    				TORRENT_PIECE_ASSERT(offset == i * block_size, pe);
    				offset += iov.iov_len;
    				ph->h.update(pe->blocks[i].buf, iov.iov_len);
    			}
    			else
    			{
    				iov.iov_base = m_disk_cache.allocate_buffer("hashing");

    				if (iov.iov_base == NULL)
    				{
    					l.lock();

    					// decrement the refcounts of the blocks we just hashed
    					for (int k = 0; k < num_locked_blocks; ++k)
    						m_disk_cache.dec_block_refcount(pe, locked_blocks[k], block_cache::ref_hashing);

    					--pe->piece_refcount;
    					pe->hashing = false;
    					delete pe->hash;
    					pe->hash = NULL;

    					m_disk_cache.maybe_free_piece(pe);

    					j->error.ec = errors::no_memory;
    					j->error.operation = storage_error::alloc_cache_piece;
    					return -1;
    				}

    				DLOG("do_hash: reading (piece: %d block: %d)\n", int(pe->piece), i);

    				time_point start_time = clock_type::now();

    				TORRENT_PIECE_ASSERT(offset == i * block_size, pe);
    				ret = j->storage->get_storage_impl()->readv(&iov, 1, j->piece
    						, offset, file_flags, j->error);

    				if (ret < 0)
    				{
    					TORRENT_ASSERT(j->error.ec && j->error.operation != 0);
    					m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base));
    					l.lock();
    					break;

relevance 0 | ../src/disk_io_thread.cpp:2697 | it would be nice to not have to lock the mutex every turn through this loop

## it would be nice to not have to lock the mutex every turn through this loop

#### ../src/disk_io_thread.cpp:2697

    			j->error.ec = error::no_memory;
    			j->error.operation = storage_error::alloc_cache_piece;
    			return -1;
    		}

    #if TORRENT_USE_ASSERTS
    		pe->piece_log.push_back(piece_log_t(j->action));
    #endif
    		TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
    			|| pe->cache_state == cached_piece_entry::read_lru2, pe);
    		++pe->piece_refcount;

    		int block_size = m_disk_cache.block_size();
    		int piece_size = j->storage->files()->piece_size(j->piece);
    		int blocks_in_piece = (piece_size + block_size - 1) / block_size;

    		file::iovec_t iov;
    		int ret = 0;
    		int offset = 0;

    		for (int i = 0; i < blocks_in_piece; ++i)
    		{
    			iov.iov_len = (std::min)(block_size, piece_size - offset);

    			// is the block already in the cache?
    			if (pe->blocks[i].buf) continue;
    			l.unlock();

    			iov.iov_base = m_disk_cache.allocate_buffer("read cache");

    			if (iov.iov_base == NULL)
    			{
    				//#error introduce a holder class that automatically increments and decrements the piece_refcount
    				--pe->piece_refcount;
    				m_disk_cache.maybe_free_piece(pe);
    				j->error.ec = errors::no_memory;
    				j->error.operation = storage_error::alloc_cache_piece;
    				return -1;
    			}

    			DLOG("do_cache_piece: reading (piece: %d block: %d)\n"
    				, int(pe->piece), i);

    			time_point start_time = clock_type::now();

    			ret = j->storage->get_storage_impl()->readv(&iov, 1, j->piece
    				, offset, file_flags, j->error);

    			if (ret < 0)
    			{
    				l.lock();

relevance 0 | ../src/enum_net.cpp:287 | get the MTU (and other interesting metrics) from the rt_msghdr instead

## get the MTU (and other interesting metrics) from the rt_msghdr instead

#### ../src/enum_net.cpp:287

    #undef ROUNDUP
    		}

    		sa = rti_info[RTAX_GATEWAY];
    		if (sa == 0
    			|| rti_info[RTAX_DST] == 0
    			|| rti_info[RTAX_NETMASK] == 0
    			|| (sa->sa_family != AF_INET
    #if TORRENT_USE_IPV6
    				&& sa->sa_family != AF_INET6
    #endif
    				))
    			return false;

    		rt_info->gateway = sockaddr_to_address(rti_info[RTAX_GATEWAY]);
    		rt_info->destination = sockaddr_to_address(rti_info[RTAX_DST]);
    		rt_info->netmask = sockaddr_to_address(rti_info[RTAX_NETMASK]
    			, rt_info->destination.is_v4() ? AF_INET : AF_INET6);
    		if_indextoname(rtm->rtm_index, rt_info->name);

    		ifreq req;
    		memset(&req, 0, sizeof(req));
    		if_indextoname(rtm->rtm_index, req.ifr_name);

    		// ignore errors here. This is best-effort
    		ioctl(s, siocgifmtu, &req);
    		rt_info->mtu = req.ifr_mtu;

    		return true;
    	}
    #endif

    #if TORRENT_USE_IFADDRS && !defined TORRENT_BUILD_SIMULATOR
    	bool iface_from_ifaddrs(ifaddrs *ifa, ip_interface &rv)
    	{
    		int family = ifa->ifa_addr->sa_family;

    		if (family != AF_INET
    #if TORRENT_USE_IPV6
    			&& family != AF_INET6
    #endif
    		)
    		{
    			return false;
    		}

    		strncpy(rv.name, ifa->ifa_name, sizeof(rv.name));
    		rv.name[sizeof(rv.name)-1] = 0;

    		// determine address
    		rv.interface_address = sockaddr_to_address(ifa->ifa_addr);

relevance 0 | ../src/file_progress.cpp:160 | it would be nice to not depend on alert_manager here

## it would be nice to not depend on alert_manager here

#### ../src/file_progress.cpp:160

    		if (m_file_progress.empty())
    			return;

    		const int piece_size = fs.piece_length();
    		boost::int64_t off = boost::int64_t(index) * piece_size;
    		int file_index = fs.file_index_at_offset(off);
    		int size = fs.piece_size(index);
    		for (; size > 0; ++file_index)
    		{
    			boost::int64_t file_offset = off - fs.file_offset(file_index);
    			TORRENT_ASSERT(file_index != fs.num_files());
    			TORRENT_ASSERT(file_offset <= fs.file_size(file_index));
    			int add = (std::min)(fs.file_size(file_index)
    				- file_offset, boost::int64_t(size));
    			m_file_progress[file_index] += add;

    			TORRENT_ASSERT(m_file_progress[file_index]
    					<= fs.file_size(file_index));

    			if (m_file_progress[file_index] >= fs.file_size(file_index) && alerts)
    			{
    				if (!fs.pad_file_at(file_index))
    				{
    					if (alerts->should_post<file_completed_alert>())
    					{
    						// this file just completed, post alert
    						alerts->emplace_alert<file_completed_alert>(h, file_index);
    					}
    				}
    			}
    			size -= add;
    			off += add;
    			TORRENT_ASSERT(size >= 0);
    		}
    	}

    #if TORRENT_USE_INVARIANT_CHECKS
    	void file_progress::check_invariant() const
    	{
    		if (m_file_progress.empty()) return;
    		for (int i = 0; i < int(m_file_progress.size()); ++i)
    		{
    			TORRENT_ASSERT(m_file_progress[i] <= m_file_sizes[i]);
    		}
    	}
    #endif
    } }

relevance 0 | ../src/metadata_transfer.cpp:365 | this is not safe. The torrent could be unloaded while we're still sending the metadata

## this is not safe. The torrent could be unloaded while we're still sending the metadata

#### ../src/metadata_transfer.cpp:365

    					= req_to_offset(req, int(m_tp.metadata().left()));

    				char msg[15];
    				char* ptr = msg;

    #ifndef TORRENT_DISABLE_LOGGING
    				m_pc.peer_log(peer_log_alert::outgoing_message, "METADATA"
    					, "start: %d total_size: %d offset: %d data_size: %d"
    					, req.first, req.second, offset.first, offset.second);
    #endif
    				// yes, we have metadata, send it
    				detail::write_uint32(11 + offset.second, ptr);
    				detail::write_uint8(bt_peer_connection::msg_extended, ptr);
    				detail::write_uint8(m_message_index, ptr);
    				// means 'data packet'
    				detail::write_uint8(1, ptr);
    				detail::write_uint32(int(m_tp.metadata().left()), ptr);
    				detail::write_uint32(offset.first, ptr);
    				m_pc.send_buffer(msg, sizeof(msg));

    				char const* metadata = m_tp.metadata().begin;
    				m_pc.append_const_send_buffer(metadata + offset.first, offset.second);
    			}
    			else
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				m_pc.peer_log(peer_log_alert::outgoing_message, "METADATA"
    					, "don't have metadata");
    #endif
    				char msg[4+3];
    				char* ptr = msg;

    				// we don't have the metadata, reply with
    				// don't have-message
    				detail::write_uint32(1 + 2, ptr);
    				detail::write_uint8(bt_peer_connection::msg_extended, ptr);
    				detail::write_uint8(m_message_index, ptr);
    				// means 'have no data'
    				detail::write_uint8(2, ptr);
    				m_pc.send_buffer(msg, sizeof(msg));
    			}
    			m_pc.setup_send();
    		}

    		virtual bool on_extended(int length
    			, int msg, buffer::const_interval body) TORRENT_OVERRIDE
    		{
    			if (msg != 14) return false;
    			if (m_message_index == 0) return false;

    			if (length > 500 * 1024)

relevance 0 | ../src/packet_buffer.cpp:180 | use compare_less_wrap for this comparison as well

## use compare_less_wrap for this comparison as well

#### ../src/packet_buffer.cpp:180

    		void** new_storage = static_cast<void**>(malloc(sizeof(void*) * new_size));
    #ifndef BOOST_NO_EXCEPTIONS
    		if (new_storage == NULL) throw std::bad_alloc();
    #endif

    		for (index_type i = 0; i < new_size; ++i)
    			new_storage[i] = 0;

    		for (index_type i = m_first; i < (m_first + m_capacity); ++i)
    			new_storage[i & (new_size - 1)] = m_storage[i & (m_capacity - 1)];

    		free(m_storage);

    		m_storage = new_storage;
    		m_capacity = new_size;
    	}

    	void* packet_buffer_impl::remove(index_type idx)
    	{
    		INVARIANT_CHECK;
    		if (idx >= m_first + m_capacity)
    			return 0;

    		if (compare_less_wrap(idx, m_first, 0xffff))
    			return 0;

    		const int mask = (m_capacity - 1);
    		void* old_value = m_storage[idx & mask];
    		m_storage[idx & mask] = 0;

    		if (old_value)
    		{
    			--m_size;
    			if (m_size == 0) m_last = m_first;
    		}

    		if (idx == m_first && m_size != 0)
    		{
    			++m_first;
    			for (boost::uint32_t i = 0; i < m_capacity; ++i, ++m_first)
    				if (m_storage[m_first & mask]) break;
    			m_first &= 0xffff;
    		}

    		if (((idx + 1) & 0xffff) == m_last && m_size != 0)
    		{
    			--m_last;
    			for (boost::uint32_t i = 0; i < m_capacity; ++i, --m_last)
    				if (m_storage[m_last & mask]) break;
    			++m_last;
    			m_last &= 0xffff;

relevance 0 | ../src/part_file.cpp:252 | what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal

## what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal

#### ../src/part_file.cpp:252

    		if (((mode & file::rw_mask) != file::read_only)
    			&& ec == boost::system::errc::no_such_file_or_directory)
    		{
    			// this means the directory the file is in doesn't exist.
    			// so create it
    			ec.clear();
    			create_directories(m_path, ec);

    			if (ec) return;
    			m_file.open(fn, mode, ec);
    		}
    	}

    	void part_file::free_piece(int piece)
    	{
    		mutex::scoped_lock l(m_mutex);

    		boost::unordered_map<int, int>::iterator i = m_piece_map.find(piece);
    		if (i == m_piece_map.end()) return;

    		m_free_slots.push_back(i->second);
    		m_piece_map.erase(i);
    		m_dirty_metadata = true;
    	}

    	void part_file::move_partfile(std::string const& path, error_code& ec)
    	{
    		mutex::scoped_lock l(m_mutex);

    		flush_metadata_impl(ec);
    		if (ec) return;

    		m_file.close();

    		if (!m_piece_map.empty())
    		{
    			std::string old_path = combine_path(m_path, m_name);
    			std::string new_path = combine_path(path, m_name);

    			rename(old_path, new_path, ec);
    			if (ec == boost::system::errc::no_such_file_or_directory)
    				ec.clear();

    			if (ec)
    			{
    				copy_file(old_path, new_path, ec);
    				if (ec) return;
    				remove(old_path, ec);
    			}
    		}

relevance 0 | ../src/part_file.cpp:375 | instead of rebuilding the whole file header and flushing it, update the slot entries as we go

## instead of rebuilding the whole file header and flushing it, update the slot entries as we go

#### ../src/part_file.cpp:375

    						TORRENT_ASSERT(j->second == slot);
    						m_free_slots.push_back(j->second);
    						m_piece_map.erase(j);
    						m_dirty_metadata = true;
    					}
    				}
    			}
    			file_offset += block_to_copy;
    			piece_offset = 0;
    			size -= block_to_copy;
    		}
    	}

    	void part_file::flush_metadata(error_code& ec)
    	{
    		mutex::scoped_lock l(m_mutex);

    		flush_metadata_impl(ec);
    	}

    	void part_file::flush_metadata_impl(error_code& ec)
    	{
    		// do we need to flush the metadata?
    		if (m_dirty_metadata == false) return;

    		if (m_piece_map.empty())
    		{
    			m_file.close();

    			// if we don't have any pieces left in the
    			// part file, remove it
    			std::string p = combine_path(m_path, m_name);
    			remove(p, ec);

    			if (ec == boost::system::errc::no_such_file_or_directory)
    				ec.clear();
    			return;
    		}

    		open_file(file::read_write, ec);
    		if (ec) return;

    		boost::scoped_array<boost::uint32_t> header(new boost::uint32_t[m_header_size]);

    		using namespace libtorrent::detail;

    		char* ptr = reinterpret_cast<char*>(header.get());

    		write_uint32(m_max_pieces, ptr);
    		write_uint32(m_piece_size, ptr);

relevance 0 | ../src/peer_connection.cpp:526 | it would be neat to be able to print this straight into the alert's stack allocator

## it would be neat to be able to print this straight into the alert's stack allocator

#### ../src/peer_connection.cpp:526

    	}

    #ifndef TORRENT_DISABLE_LOGGING
    	void peer_connection::peer_log(peer_log_alert::direction_t direction
    		, char const* event) const
    	{
    		peer_log(direction, event, "");
    	}

    	TORRENT_FORMAT(4,5)
    	void peer_connection::peer_log(peer_log_alert::direction_t direction
    		, char const* event, char const* fmt, ...) const
    	{
    		TORRENT_ASSERT(is_single_thread());

    		if (!m_ses.alerts().should_post<peer_log_alert>()) return;

    		va_list v;
    		va_start(v, fmt);

    		char buf[512];
    		vsnprintf(buf, sizeof(buf), fmt, v);
    		va_end(v);

    		torrent_handle h;
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		if (t) h = t->get_handle();

    		m_ses.alerts().emplace_alert<peer_log_alert>(
    			h, m_remote, m_peer_id, direction, event, buf);
    	}
    #endif

    #ifndef TORRENT_DISABLE_EXTENSIONS
    	void peer_connection::add_extension(boost::shared_ptr<peer_plugin> ext)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		m_extensions.push_back(ext);
    	}

    	peer_plugin const* peer_connection::find_plugin(char const* type)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		for (extension_list_t::iterator i = m_extensions.begin()
    			, end(m_extensions.end()); i != end; ++i)
    		{
    			if (strcmp((*i)->type(), type) == 0) return (*i).get();
    		}
    		return 0;
    	}
    #endif

relevance 0 | ../src/peer_connection.cpp:1037 | this should be the global download rate

## this should be the global download rate

#### ../src/peer_connection.cpp:1037

    		int rate = 0;

    		// if we haven't received any data recently, the current download rate
    		// is not representative
    		if (aux::time_now() - m_last_piece > seconds(30) && m_download_rate_peak > 0)
    		{
    			rate = m_download_rate_peak;
    		}
    		else if (aux::time_now() - m_last_unchoked < seconds(5)
    			&& m_statistics.total_payload_upload() < 2 * 0x4000)
    		{
    			// if we're have only been unchoked for a short period of time,
    			// we don't know what rate we can get from this peer. Instead of assuming
    			// the lowest possible rate, assume the average.

    			int peers_with_requests = stats_counters()[counters::num_peers_down_requests];
    			// avoid division by 0
    			if (peers_with_requests == 0) peers_with_requests = 1;

    			rate = t->statistics().transfer_rate(stat::download_payload) / peers_with_requests;
    		}
    		else
    		{
    			// current download rate in bytes per seconds
    			rate = m_statistics.transfer_rate(stat::download_payload);
    		}

    		// avoid division by zero
    		if (rate < 50) rate = 50;

    		// average of current rate and peak
    //		rate = (rate + m_download_rate_peak) / 2;

    		return milliseconds((m_outstanding_bytes + extra_bytes
    			+ m_queued_time_critical * t->block_size() * 1000) / rate);
    	}

    	void peer_connection::add_stat(boost::int64_t downloaded, boost::int64_t uploaded)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		m_statistics.add_stat(downloaded, uploaded);
    	}

    	void peer_connection::received_bytes(int bytes_payload, int bytes_protocol)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		m_statistics.received_bytes(bytes_payload, bytes_protocol);
    		if (m_ignore_stats) return;
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		if (!t) return;

relevance 0 | ../src/peer_connection.cpp:3380 | sort the allowed fast set in priority order

## sort the allowed fast set in priority order

#### ../src/peer_connection.cpp:3380

    		// if the peer has the piece and we want
    		// to download it, request it
    		if (int(m_have_piece.size()) > index
    			&& m_have_piece[index]
    			&& !t->has_piece_passed(index)
    			&& t->valid_metadata()
    			&& t->has_picker()
    			&& t->picker().piece_priority(index) > 0)
    		{
    			t->peer_is_interesting(*this);
    		}
    	}

    	std::vector<int> const& peer_connection::allowed_fast()
    	{
    		TORRENT_ASSERT(is_single_thread());
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		TORRENT_ASSERT(t);

    		return m_allowed_fast;
    	}

    	bool peer_connection::can_request_time_critical() const
    	{
    		TORRENT_ASSERT(is_single_thread());
    		if (has_peer_choked() || !is_interesting()) return false;
    		if (int(m_download_queue.size()) + int(m_request_queue.size())
    			> m_desired_queue_size * 2) return false;
    		if (on_parole()) return false;
    		if (m_disconnecting) return false;
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		TORRENT_ASSERT(t);
    		if (t->upload_mode()) return false;

    		// ignore snubbed peers, since they're not likely to return pieces in a
    		// timely manner anyway
    		if (m_snubbed) return false;
    		return true;
    	}

    	bool peer_connection::make_time_critical(piece_block const& block)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		std::vector<pending_block>::iterator rit = std::find_if(m_request_queue.begin()
    			, m_request_queue.end(), has_block(block));
    		if (rit == m_request_queue.end()) return false;
    #if TORRENT_USE_ASSERTS
    		boost::shared_ptr<torrent> t = m_torrent.lock();
    		TORRENT_ASSERT(t);
    		TORRENT_ASSERT(t->has_picker());

relevance 0 | ../src/peer_connection.cpp:6202 | The stats checks can not be honored when authenticated encryption is in use because we may have encrypted data which we cannot authenticate yet

## The stats checks can not be honored when authenticated encryption is in use because we may have encrypted data which we cannot authenticate yet

#### ../src/peer_connection.cpp:6202

    #ifndef TORRENT_DISABLE_LOGGING
    			peer_log(peer_log_alert::incoming, "READ"
    				, "%d bytes", int(bytes_transferred));
    #endif
    			// correct the dl quota usage, if not all of the buffer was actually read
    			TORRENT_ASSERT(int(bytes_transferred) <= m_quota[download_channel]);
    			m_quota[download_channel] -= bytes_transferred;

    			if (m_disconnecting)
    			{
    				trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6());
    				return;
    			}

    			TORRENT_ASSERT(bytes_transferred > 0);
    			m_recv_buffer.received(bytes_transferred);

    			int bytes = bytes_transferred;
    			int sub_transferred = 0;
    			do {
    #if 0
    				boost::int64_t cur_payload_dl = m_statistics.last_payload_downloaded();
    				boost::int64_t cur_protocol_dl = m_statistics.last_protocol_downloaded();
    #endif
    				sub_transferred = m_recv_buffer.advance_pos(bytes);
    				on_receive(error, sub_transferred);
    				bytes -= sub_transferred;
    				TORRENT_ASSERT(sub_transferred > 0);

    #if 0
    				TORRENT_ASSERT(m_statistics.last_payload_downloaded() - cur_payload_dl >= 0);
    				TORRENT_ASSERT(m_statistics.last_protocol_downloaded() - cur_protocol_dl >= 0);
    				boost::int64_t stats_diff = m_statistics.last_payload_downloaded() - cur_payload_dl +
    					m_statistics.last_protocol_downloaded() - cur_protocol_dl;
    				TORRENT_ASSERT(stats_diff == int(sub_transferred));
    #endif
    				if (m_disconnecting) return;

    			} while (bytes > 0 && sub_transferred > 0);

    			m_recv_buffer.normalize();

    			TORRENT_ASSERT(m_recv_buffer.pos_at_end());
    			TORRENT_ASSERT(m_recv_buffer.packet_size() > 0);

    			if (m_peer_choked)
    			{
    				m_recv_buffer.clamp_size();
    			}

    			if (num_loops > read_loops) break;

relevance 0 | ../src/piece_picker.cpp:2056 | this could probably be optimized by incrementally calling partial_sort to sort one more element in the list. Because chances are that we'll just need a single piece, and once we've picked from it we're done. Sorting the rest of the list in that case is a waste of time.

## this could probably be optimized by incrementally calling partial_sort to sort one more element in the list. Because chances are that we'll just need a single piece, and once we've picked from it we're done. Sorting the rest of the list in that case is a waste of time.

#### ../src/piece_picker.cpp:2056

    				pc.inc_stats_counter(counters::piece_picker_partial_loops);

    				// in time critical mode, only pick high priority pieces
    				if ((options & time_critical_mode)
    					&& piece_priority(i->index) != priority_levels - 1)
    					continue;

    				if (!is_piece_free(i->index, pieces)) continue;

    				TORRENT_ASSERT(m_piece_map[i->index].download_queue()
    					== piece_pos::piece_downloading);

    				ordered_partials[num_ordered_partials++] = &*i;
    			}

    			// now, sort the list.
    			if (options & rarest_first)
    			{
    				ret |= picker_log_alert::rarest_first_partials;

    				std::sort(ordered_partials, ordered_partials + num_ordered_partials
    					, boost::bind(&piece_picker::partial_compare_rarest_first, this
    						, _1, _2));
    			}

    			for (int i = 0; i < num_ordered_partials; ++i)
    			{
    				ret |= picker_log_alert::prioritize_partials;

    				num_blocks = add_blocks_downloading(*ordered_partials[i], pieces
    					, interesting_blocks, backup_blocks, backup_blocks2
    					, num_blocks, prefer_contiguous_blocks, peer, options);
    				if (num_blocks <= 0) return ret;
    				if (int(backup_blocks.size()) >= num_blocks
    					&& int(backup_blocks2.size()) >= num_blocks)
    					break;
    			}

    			num_blocks = append_blocks(interesting_blocks, backup_blocks
    				, num_blocks);
    			if (num_blocks <= 0) return ret;

    			num_blocks = append_blocks(interesting_blocks, backup_blocks2
    				, num_blocks);
    			if (num_blocks <= 0) return ret;
    		}

    		if (!suggested_pieces.empty())
    		{
    			for (std::vector<int>::const_iterator i = suggested_pieces.begin();
    				i != suggested_pieces.end(); ++i)

relevance 0 | ../src/piece_picker.cpp:2578 | when expanding pieces for cache stripe reasons, the !downloading condition doesn't make much sense

## when expanding pieces for cache stripe reasons, the !downloading condition doesn't make much sense

#### ../src/piece_picker.cpp:2578

    		TORRENT_ASSERT(index < int(m_piece_map.size()) || m_piece_map.empty());
    		if (index + 1 == int(m_piece_map.size()))
    			return m_blocks_in_last_piece;
    		else
    			return m_blocks_per_piece;
    	}

    	bool piece_picker::is_piece_free(int piece, bitfield const& bitmask) const
    	{
    		TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
    		return bitmask[piece]
    			&& !m_piece_map[piece].have()
    			&& !m_piece_map[piece].filtered();
    	}

    	bool piece_picker::can_pick(int piece, bitfield const& bitmask) const
    	{
    		TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
    		return bitmask[piece]
    			&& !m_piece_map[piece].have()
    			&& !m_piece_map[piece].downloading()
    			&& !m_piece_map[piece].filtered();
    	}

    #if TORRENT_USE_INVARIANT_CHECKS
    	void piece_picker::check_peers()
    	{
    		for (std::vector<block_info>::iterator i = m_block_info.begin()
    			, end(m_block_info.end()); i != end; ++i)
    		{
    			TORRENT_ASSERT(i->peer == 0 || static_cast<torrent_peer*>(i->peer)->in_use);
    		}
    	}
    #endif

    	void piece_picker::clear_peer(torrent_peer* peer)
    	{
    		for (std::vector<block_info>::iterator i = m_block_info.begin()
    			, end(m_block_info.end()); i != end; ++i)
    		{
    			if (i->peer == peer) i->peer = 0;
    		}
    	}

    	// the first bool is true if this is the only peer that has requested and downloaded
    	// blocks from this piece.
    	// the second bool is true if this is the only active peer that is requesting
    	// and downloading blocks from this piece. Active means having a connection.

relevance 0 | ../src/session_impl.cpp:515 | there's no rule here to make uTP connections not have the global or local rate limits apply to it. This used to be the default.

## there's no rule here to make uTP connections not have the global or local rate limits apply to it. This used to be the default.

#### ../src/session_impl.cpp:515

    		m_global_class = m_classes.new_peer_class("global");
    		m_tcp_peer_class = m_classes.new_peer_class("tcp");
    		m_local_peer_class = m_classes.new_peer_class("local");
    		// local peers are always unchoked
    		m_classes.at(m_local_peer_class)->ignore_unchoke_slots = true;
    		// local peers are allowed to exceed the normal connection
    		// limit by 50%
    		m_classes.at(m_local_peer_class)->connection_limit_factor = 150;

    		TORRENT_ASSERT(m_global_class == session::global_peer_class_id);
    		TORRENT_ASSERT(m_tcp_peer_class == session::tcp_peer_class_id);
    		TORRENT_ASSERT(m_local_peer_class == session::local_peer_class_id);

    		init_peer_class_filter(true);

    		// TCP, SSL/TCP and I2P connections should be assigned the TCP peer class
    		m_peer_class_type_filter.add(peer_class_type_filter::tcp_socket, m_tcp_peer_class);
    		m_peer_class_type_filter.add(peer_class_type_filter::ssl_tcp_socket, m_tcp_peer_class);
    		m_peer_class_type_filter.add(peer_class_type_filter::i2p_socket, m_tcp_peer_class);

    #ifndef TORRENT_DISABLE_LOGGING

    		session_log("config: %s version: %s revision: %s"
    			, TORRENT_CFG_STRING
    			, LIBTORRENT_VERSION
    			, LIBTORRENT_REVISION);

    #endif // TORRENT_DISABLE_LOGGING

    		// ---- auto-cap max connections ----
    		int const max_files = max_open_files();
    		// deduct some margin for epoll/kqueue, log files,
    		// futexes, shared objects etc.
    		// 80% of the available file descriptors should go to connections
    		m_settings.set_int(settings_pack::connections_limit, std::min(
    			m_settings.get_int(settings_pack::connections_limit)
    			, std::max(5, (max_files - 20) * 8 / 10)));
    		// 20% goes towards regular files (see disk_io_thread)
    #ifndef TORRENT_DISABLE_LOGGING
    		session_log("   max connections: %d", m_settings.get_int(settings_pack::connections_limit));
    		session_log("   max files: %d", max_files);

    		session_log(" generated peer ID: %s", m_peer_id.to_string().c_str());
    #endif

    		boost::shared_ptr<settings_pack> copy = boost::make_shared<settings_pack>(pack);
    		m_io_service.post(boost::bind(&session_impl::init, this, copy));
    	}

    	void session_impl::init(boost::shared_ptr<settings_pack> pack)

relevance 0 | ../src/session_impl.cpp:1651 | it would be nice to reserve() these vectors up front

## it would be nice to reserve() these vectors up front

#### ../src/session_impl.cpp:1651

    			bandwidth_channel* ch = &p->channel[peer_connection::download_channel];
    			if (use_quota_overhead(ch, amount_down))
    				ret |= 1 << peer_connection::download_channel;
    			ch = &p->channel[peer_connection::upload_channel];
    			if (use_quota_overhead(ch, amount_up))
    				ret |= 1 << peer_connection::upload_channel;
    		}
    		return ret;
    	}

    	// session_impl is responsible for deleting 'pack'
    	void session_impl::apply_settings_pack(boost::shared_ptr<settings_pack> pack)
    	{
    		INVARIANT_CHECK;
    		apply_settings_pack_impl(*pack);
    	}

    	settings_pack session_impl::get_settings() const
    	{
    		settings_pack ret;
    		for (int i = settings_pack::string_type_base;
    			i < settings_pack::max_string_setting_internal; ++i)
    		{
    			ret.set_str(i, m_settings.get_str(i));
    		}
    		for (int i = settings_pack::int_type_base;
    			i < settings_pack::max_int_setting_internal; ++i)
    		{
    			ret.set_int(i, m_settings.get_int(i));
    		}
    		for (int i = settings_pack::bool_type_base;
    			i < settings_pack::max_bool_setting_internal; ++i)
    		{
    			ret.set_bool(i, m_settings.get_bool(i));
    		}
    		return ret;
    	}

    	void session_impl::apply_settings_pack_impl(settings_pack const& pack)
    	{
    		bool reopen_listen_port =
    			(pack.has_val(settings_pack::ssl_listen)
    				&& pack.get_int(settings_pack::ssl_listen)
    					!= m_settings.get_int(settings_pack::ssl_listen))
    			|| (pack.has_val(settings_pack::listen_interfaces)
    				&& pack.get_str(settings_pack::listen_interfaces)
    					!= m_settings.get_str(settings_pack::listen_interfaces));

    		apply_pack(&pack, m_settings, this);

    		m_disk_thread.set_settings(&pack, m_alerts);

relevance 0 | ../src/session_impl.cpp:1890 | instead of having a special case for this, just make the default listen interfaces be "0.0.0.0:6881,[::]:6881" and use the generic path. That would even allow for not listening at all.

## instead of having a special case for this, just make the default listen interfaces be "0.0.0.0:6881,[::]:6881" and use the generic path. That would even allow for not listening at all.

#### ../src/session_impl.cpp:1890

    		error_code ec;

    		int listen_port_retries = m_settings.get_int(settings_pack::max_retry_port_bind);

    retry:

    		// close the open listen sockets
    		// close the listen sockets
    		for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
    			, end(m_listen_sockets.end()); i != end; ++i)
    			i->sock->close(ec);
    		m_listen_sockets.clear();
    		m_stats_counters.set_value(counters::has_incoming_connections, 0);
    		ec.clear();

    		if (m_abort) return;

    		m_ipv6_interface = tcp::endpoint();
    		m_ipv4_interface = tcp::endpoint();

    		if (m_listen_interfaces.empty())
    		{
    			// this means we should open two listen sockets
    			// one for IPv4 and one for IPv6
    			listen_socket_t s = setup_listener("0.0.0.0", boost::asio::ip::tcp::v4()
    				, m_listen_interface.port()
    				, flags, ec);

    			if (!ec && s.sock)
    			{
    				// update the listen_interface member with the
    				// actual port we ended up listening on, so that the other
    				// sockets can be bound to the same one
    				m_listen_interface.port(s.external_port);

    				TORRENT_ASSERT(!m_abort);
    				m_listen_sockets.push_back(s);
    			}

    #ifdef TORRENT_USE_OPENSSL
    			if (m_settings.get_int(settings_pack::ssl_listen))
    			{
    				s = setup_listener("0.0.0.0", boost::asio::ip::tcp::v4()
    					, m_settings.get_int(settings_pack::ssl_listen)
    					, flags | open_ssl_socket, ec);

    				if (!ec && s.sock)
    				{
    					TORRENT_ASSERT(!m_abort);
    					m_listen_sockets.push_back(s);
    				}

relevance 0 | ../src/session_impl.cpp:2830 | should this function take a shared_ptr instead?

## should this function take a shared_ptr instead?

#### ../src/session_impl.cpp:2830

    			// as soon as it's received the handshake, it needs to either
    			// disconnect or pick another peer to disconnect
    			if (num_connections() >= limit)
    				c->peer_exceeds_limit();

    			TORRENT_ASSERT(!c->m_in_constructor);
    			m_connections.insert(c);
    			c->start();
    		}
    	}

    	void session_impl::setup_socket_buffers(socket_type& s)
    	{
    		error_code ec;
    		set_socket_buffer_size(s, m_settings, ec);
    	}

    	// if cancel_with_cq is set, the peer connection is
    	// currently expected to be scheduled for a connection
    	// with the connection queue, and should be cancelled
    	void session_impl::close_connection(peer_connection* p
    		, error_code const& ec)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		boost::shared_ptr<peer_connection> sp(p->self());

    		// someone else is holding a reference, it's important that
    		// it's destructed from the network thread. Make sure the
    		// last reference is held by the network thread.
    		if (!sp.unique())
    			m_undead_peers.push_back(sp);

    // too expensive
    //		INVARIANT_CHECK;

    #ifdef TORRENT_DEBUG
    //		for (aux::session_impl::torrent_map::const_iterator i = m_torrents.begin()
    //			, end(m_torrents.end()); i != end; ++i)
    //			TORRENT_ASSERT(!i->second->has_peer((peer_connection*)p));
    #endif

    #ifndef TORRENT_DISABLE_LOGGING
    		session_log(" CLOSING CONNECTION %s : %s"
    			, print_endpoint(p->remote()).c_str(), ec.message().c_str());
    #else
    		TORRENT_UNUSED(ec);
    #endif

    		TORRENT_ASSERT(p->is_disconnecting());

    		TORRENT_ASSERT(sp.use_count() > 0);

relevance 0 | ../src/session_impl.cpp:3224 | have a separate list for these connections, instead of having to loop through all of them

## have a separate list for these connections, instead of having to loop through all of them

#### ../src/session_impl.cpp:3224

    		if (!m_paused) m_auto_manage_time_scaler--;
    		if (m_auto_manage_time_scaler < 0)
    		{
    			m_auto_manage_time_scaler = settings().get_int(settings_pack::auto_manage_interval);
    			recalculate_auto_managed_torrents();
    		}

    		// --------------------------------------------------------------
    		// check for incoming connections that might have timed out
    		// --------------------------------------------------------------

    		for (connection_map::iterator i = m_connections.begin();
    			i != m_connections.end();)
    		{
    			peer_connection* p = (*i).get();
    			++i;
    			// ignore connections that already have a torrent, since they
    			// are ticked through the torrents' second_tick
    			if (!p->associated_torrent().expired()) continue;

    			int timeout = m_settings.get_int(settings_pack::handshake_timeout);
    #if TORRENT_USE_I2P
    			timeout *= is_i2p(*p->get_socket()) ? 4 : 1;
    #endif
    			if (m_last_tick - p->connected_time () > seconds(timeout))
    				p->disconnect(errors::timed_out, op_bittorrent);
    		}

    		// --------------------------------------------------------------
    		// second_tick every torrent (that wants it)
    		// --------------------------------------------------------------

    #if TORRENT_DEBUG_STREAMING > 0
    		printf("\033[2J\033[0;0H");
    #endif

    		std::vector<torrent*>& want_tick = m_torrent_lists[torrent_want_tick];
    		for (int i = 0; i < int(want_tick.size()); ++i)
    		{
    			torrent& t = *want_tick[i];
    			TORRENT_ASSERT(t.want_tick());
    			TORRENT_ASSERT(!t.is_aborted());

    			t.second_tick(tick_interval_ms);

    			// if the call to second_tick caused the torrent
    			// to no longer want to be ticked (i.e. it was
    			// removed from the list) we need to back up the counter
    			// to not miss the torrent after it
    			if (!t.want_tick()) --i;
    		}

relevance 0 | ../src/session_impl.cpp:3257 | this should apply to all bandwidth channels

## this should apply to all bandwidth channels

#### ../src/session_impl.cpp:3257

    #if TORRENT_DEBUG_STREAMING > 0
    		printf("\033[2J\033[0;0H");
    #endif

    		std::vector<torrent*>& want_tick = m_torrent_lists[torrent_want_tick];
    		for (int i = 0; i < int(want_tick.size()); ++i)
    		{
    			torrent& t = *want_tick[i];
    			TORRENT_ASSERT(t.want_tick());
    			TORRENT_ASSERT(!t.is_aborted());

    			t.second_tick(tick_interval_ms);

    			// if the call to second_tick caused the torrent
    			// to no longer want to be ticked (i.e. it was
    			// removed from the list) we need to back up the counter
    			// to not miss the torrent after it
    			if (!t.want_tick()) --i;
    		}

    		if (m_settings.get_bool(settings_pack::rate_limit_ip_overhead))
    		{
    			int up_limit = upload_rate_limit(m_global_class);
    			int down_limit = download_rate_limit(m_global_class);

    			if (down_limit > 0
    				&& m_stat.download_ip_overhead() >= down_limit
    				&& m_alerts.should_post<performance_alert>())
    			{
    				m_alerts.emplace_alert<performance_alert>(torrent_handle()
    					, performance_alert::download_limit_too_low);
    			}

    			if (up_limit > 0
    				&& m_stat.upload_ip_overhead() >= up_limit
    				&& m_alerts.should_post<performance_alert>())
    			{
    				m_alerts.emplace_alert<performance_alert>(torrent_handle()
    					, performance_alert::upload_limit_too_low);
    			}
    		}

    		m_peak_up_rate = (std::max)(m_stat.upload_rate(), m_peak_up_rate);
    		m_peak_down_rate = (std::max)(m_stat.download_rate(), m_peak_down_rate);

    		m_stat.second_tick(tick_interval_ms);

    		// --------------------------------------------------------------
    		// scrape paused torrents that are auto managed
    		// (unless the session is paused)
    		// --------------------------------------------------------------

relevance 0 | ../src/session_impl.cpp:4059 | use a lower limit than m_settings.connections_limit to allocate the to 10% or so of connection slots for incoming connections cap this at max - 1, since we may add one below

## use a lower limit than m_settings.connections_limit to allocate the to 10% or so of connection slots for incoming connections cap this at max - 1, since we may add one below

#### ../src/session_impl.cpp:4059

    		// robin fashion, so that every torrent is equally likely to connect to a
    		// peer

    		// boost connections are connections made by torrent connection
    		// boost, which are done immediately on a tracker response. These
    		// connections needs to be deducted from this second
    		if (m_boost_connections > 0)
    		{
    			if (m_boost_connections > max_connections)
    			{
    				m_boost_connections -= max_connections;
    				max_connections = 0;
    			}
    			else
    			{
    				max_connections -= m_boost_connections;
    				m_boost_connections = 0;
    			}
    		}

    		int const limit = std::min(m_settings.get_int(settings_pack::connections_limit)
    			- num_connections(), std::numeric_limits<int>::max() - 1);

    		// this logic is here to smooth out the number of new connection
    		// attempts over time, to prevent connecting a large number of
    		// sockets, wait 10 seconds, and then try again
    		if (m_settings.get_bool(settings_pack::smooth_connects) && max_connections > (limit+1) / 2)
    			max_connections = (limit+1) / 2;

    		std::vector<torrent*>& want_peers_download = m_torrent_lists[torrent_want_peers_download];
    		std::vector<torrent*>& want_peers_finished = m_torrent_lists[torrent_want_peers_finished];

    		// if no torrent want any peers, just return
    		if (want_peers_download.empty() && want_peers_finished.empty()) return;

    		// if we don't have any connection attempt quota, return
    		if (max_connections <= 0) return;

    		INVARIANT_CHECK;

    		int steps_since_last_connect = 0;
    		int num_torrents = int(want_peers_finished.size() + want_peers_download.size());
    		for (;;)
    		{
    			if (m_next_downloading_connect_torrent >= int(want_peers_download.size()))
    				m_next_downloading_connect_torrent = 0;

    			if (m_next_finished_connect_torrent >= int(want_peers_finished.size()))
    				m_next_finished_connect_torrent = 0;

    			torrent* t = NULL;

relevance 0 | ../src/session_impl.cpp:4211 | post a message to have this happen immediately instead of waiting for the next tick

## post a message to have this happen immediately instead of waiting for the next tick

#### ../src/session_impl.cpp:4211

    				continue;
    			}

    			if (!p->is_peer_interested()
    				|| p->is_disconnecting()
    				|| p->is_connecting())
    			{
    				// this peer is not unchokable. So, if it's unchoked
    				// already, make sure to choke it.
    				if (p->is_choked())
    				{
    					p->reset_choke_counters();
    					continue;
    				}
    				if (pi && pi->optimistically_unchoked)
    				{
    					m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
    					pi->optimistically_unchoked = false;
    					// force a new optimistic unchoke
    					m_optimistic_unchoke_time_scaler = 0;
    				}
    				t->choke_peer(*p);
    				p->reset_choke_counters();
    				continue;
    			}

    			peers.push_back(p.get());
    		}

    		// the unchoker wants an estimate of our upload rate capacity
    		// (used by bittyrant)
    		int max_upload_rate = upload_rate_limit(m_global_class);
    		if (m_settings.get_int(settings_pack::choking_algorithm)
    			== settings_pack::bittyrant_choker
    			&& max_upload_rate == 0)
    		{
    			// we don't know at what rate we can upload. If we have a
    			// measurement of the peak, use that + 10kB/s, otherwise
    			// assume 20 kB/s
    			max_upload_rate = (std::max)(20000, m_peak_up_rate + 10000);
    			if (m_alerts.should_post<performance_alert>())
    				m_alerts.emplace_alert<performance_alert>(torrent_handle()
    					, performance_alert::bittyrant_with_no_uplimit);
    		}

    		int const allowed_upload_slots = unchoke_sort(peers, max_upload_rate
    			, unchoke_interval, m_settings);

    		m_stats_counters.set_value(counters::num_unchoke_slots
    			, allowed_upload_slots);

relevance 0 | ../src/session_impl.cpp:4599 | it might be a nice feature here to limit the number of torrents to send in a single update. By just posting the first n torrents, they would nicely be round-robined because the torrent lists are always pushed back. Perhaps the status_update_alert could even have a fixed array of n entries rather than a vector, to further improve memory locality.

## it might be a nice feature here to limit the number of torrents to send in a single update. By just posting the first n torrents, they would nicely be round-robined because the torrent lists are always pushed back. Perhaps the status_update_alert could even have a fixed array of n entries rather than a vector, to further improve memory locality.

#### ../src/session_impl.cpp:4599

    			t->status(&*i, flags);
    		}
    	}

    	void session_impl::post_torrent_updates(boost::uint32_t flags)
    	{
    		INVARIANT_CHECK;

    		TORRENT_ASSERT(is_single_thread());

    		std::vector<torrent*>& state_updates
    			= m_torrent_lists[aux::session_impl::torrent_state_updates];

    #if TORRENT_USE_ASSERTS
    		m_posting_torrent_updates = true;
    #endif

    		std::vector<torrent_status> status;
    		status.reserve(state_updates.size());

    		for (std::vector<torrent*>::iterator i = state_updates.begin()
    			, end(state_updates.end()); i != end; ++i)
    		{
    			torrent* t = *i;
    			TORRENT_ASSERT(t->m_links[aux::session_impl::torrent_state_updates].in_list());
    			status.push_back(torrent_status());
    			// querying accurate download counters may require
    			// the torrent to be loaded. Loading a torrent, and evicting another
    			// one will lead to calling state_updated(), which screws with
    			// this list while we're working on it, and break things
    			t->status(&status.back(), flags);
    			t->clear_in_state_update();
    		}
    		state_updates.clear();

    #if TORRENT_USE_ASSERTS
    		m_posting_torrent_updates = false;
    #endif

    		m_alerts.emplace_alert<state_update_alert>(status);
    	}

    	void session_impl::post_session_stats()
    	{
    		m_disk_thread.update_stats_counters(m_stats_counters);

    #ifndef TORRENT_DISABLE_DHT
    		if (m_dht)
    			m_dht->update_stats_counters(m_stats_counters);
    #endif

relevance 0 | ../src/session_impl.cpp:4953 | this logic could probably be less spaghetti looking by being moved to a function with early exits

## this logic could probably be less spaghetti looking by being moved to a function with early exits

#### ../src/session_impl.cpp:4953

    		{
    			ec = errors::session_is_closing;
    			return std::make_pair(ptr_t(), false);
    		}

    		// figure out the info hash of the torrent and make sure params.info_hash
    		// is set correctly
    		if (params.ti) params.info_hash = params.ti->info_hash();
    		else if (!params.url.empty())
    		{
    			// in order to avoid info-hash collisions, for
    			// torrents where we don't have an info-hash, but
    			// just a URL, set the temporary info-hash to the
    			// hash of the URL. This will be changed once we
    			// have the actual .torrent file
    			params.info_hash = hasher(&params.url[0], params.url.size()).final();
    		}

    		// we don't have a torrent file. If the user provided
    		// resume data, there may be some metadata in there
    		if ((!params.ti || !params.ti->is_valid())
    			&& !params.resume_data.empty())
    		{
    			int pos;
    			error_code err;
    			bdecode_node root;
    			bdecode_node info;
    #ifndef TORRENT_DISABLE_LOGGING
    			session_log("adding magnet link with resume data");
    #endif
    			if (bdecode(&params.resume_data[0], &params.resume_data[0]
    					+ params.resume_data.size(), root, err, &pos) == 0
    				&& root.type() == bdecode_node::dict_t
    				&& (info = root.dict_find_dict("info")))
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				session_log("found metadata in resume data");
    #endif
    				// verify the info-hash of the metadata stored in the resume file matches
    				// the torrent we're loading

    				std::pair<char const*, int> const buf = info.data_section();
    				sha1_hash const resume_ih = hasher(buf.first, buf.second).final();

    				// if url is set, the info_hash is not actually the info-hash of the
    				// torrent, but the hash of the URL, until we have the full torrent
    				// only require the info-hash to match if we actually passed in one
    				if (resume_ih == params.info_hash
    					|| !params.url.empty()
    					|| params.info_hash.is_all_zeros())
    				{

relevance 0 | ../src/session_impl.cpp:5551 | perhaps this function should not exist when logging is disabled

## perhaps this function should not exist when logging is disabled

#### ../src/session_impl.cpp:5551

    		TORRENT_ASSERT(is_single_thread());

    		INVARIANT_CHECK;

    		boost::shared_ptr<torrent> t = find_torrent(ih).lock();
    		if (!t) return;
    		// don't add peers from lsd to private torrents
    		if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
    			&& !m_settings.get_bool(settings_pack::allow_i2p_mixed))) return;

    #ifndef TORRENT_DISABLE_LOGGING
    		session_log("added peer from local discovery: %s", print_endpoint(peer).c_str());
    #endif
    		t->add_peer(peer, peer_info::lsd);
    		t->do_connect_boost();

    		if (m_alerts.should_post<lsd_peer_alert>())
    			m_alerts.emplace_alert<lsd_peer_alert>(t->get_handle(), peer);
    	}

    	void session_impl::on_port_map_log(
    		char const* msg, int map_transport)
    	{
    #ifndef TORRENT_DISABLE_LOGGING
    		TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);
    		// log message
    		if (m_alerts.should_post<portmap_log_alert>())
    			m_alerts.emplace_alert<portmap_log_alert>(map_transport, msg);
    #else
    		TORRENT_UNUSED(msg);
    		TORRENT_UNUSED(map_transport);
    #endif
    	}

    	void session_impl::on_port_mapping(int mapping, address const& ip, int port
    		, int protocol, error_code const& ec, int map_transport)
    	{
    		TORRENT_ASSERT(is_single_thread());

    		TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);

    		if (mapping == m_udp_mapping[map_transport] && port != 0)
    		{
    			m_external_udp_port = port;
    			if (m_alerts.should_post<portmap_alert>())
    				m_alerts.emplace_alert<portmap_alert>(mapping, port
    					, map_transport, protocol == natpmp::udp
    					? portmap_alert::udp : portmap_alert::tcp);
    			return;
    		}

relevance 0 | ../src/settings_pack.cpp:589 | it would be nice to reserve() these vectors up front

## it would be nice to reserve() these vectors up front

#### ../src/settings_pack.cpp:589

    			s.set_str(settings_pack::string_type_base + i, str_settings[i].default_value);
    			TORRENT_ASSERT(s.get_str(settings_pack::string_type_base + i) == str_settings[i].default_value);
    		}

    		for (int i = 0; i < settings_pack::num_int_settings; ++i)
    		{
    			s.set_int(settings_pack::int_type_base + i, int_settings[i].default_value);
    			TORRENT_ASSERT(s.get_int(settings_pack::int_type_base + i) == int_settings[i].default_value);
    		}

    		for (int i = 0; i < settings_pack::num_bool_settings; ++i)
    		{
    			s.set_bool(settings_pack::bool_type_base + i, bool_settings[i].default_value);
    			TORRENT_ASSERT(s.get_bool(settings_pack::bool_type_base + i) == bool_settings[i].default_value);
    		}
    	}

    	settings_pack default_settings()
    	{
    		settings_pack ret;
    		for (int i = 0; i < settings_pack::num_string_settings; ++i)
    		{
    			if (str_settings[i].default_value == NULL) continue;
    			ret.set_str(settings_pack::string_type_base + i, str_settings[i].default_value);
    		}

    		for (int i = 0; i < settings_pack::num_int_settings; ++i)
    		{
    			ret.set_int(settings_pack::int_type_base + i, int_settings[i].default_value);
    		}

    		for (int i = 0; i < settings_pack::num_bool_settings; ++i)
    		{
    			ret.set_bool(settings_pack::bool_type_base + i, bool_settings[i].default_value);
    		}
    		return ret;
    	}

    	void apply_pack(settings_pack const* pack, aux::session_settings& sett
    		, aux::session_impl* ses)
    	{
    		typedef void (aux::session_impl::*fun_t)();
    		std::vector<fun_t> callbacks;

    		for (std::vector<std::pair<boost::uint16_t, std::string> >::const_iterator i = pack->m_strings.begin()
    			, end(pack->m_strings.end()); i != end; ++i)
    		{
    			// disregard setting indices that are not string types
    			if ((i->first & settings_pack::type_mask) != settings_pack::string_type_base)
    				continue;

relevance 0 | ../src/storage.cpp:945 | make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance maybe use the same format as .torrent files and reuse some code from torrent_info

## make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance maybe use the same format as .torrent files and reuse some code from torrent_info

#### ../src/storage.cpp:945

    					TORRENT_ASSERT_VAL(s.file_size == file_size, file_size);
    				}
    				else
    				{
    					TORRENT_ASSERT_VAL(file_size == 0, file_size);
    				}
    			}
    #endif

    			fl.push_back(entry(entry::list_t));
    			entry::list_type& p = fl.back().list();
    			p.push_back(entry(file_size));
    			p.push_back(entry(file_time));
    		}
    	}

    	bool default_storage::verify_resume_data(bdecode_node const& rd
    		, std::vector<std::string> const* links
    		, storage_error& ec)
    	{
    		bdecode_node mapped_files = rd.dict_find_list("mapped_files");
    		if (mapped_files && mapped_files.list_size() == m_files.num_files())
    		{
    			m_mapped_files.reset(new file_storage(m_files));
    			for (int i = 0; i < m_files.num_files(); ++i)
    			{
    				std::string new_filename = mapped_files.list_string_value_at(i);
    				if (new_filename.empty()) continue;
    				m_mapped_files->rename_file(i, new_filename);
    			}
    		}

    		bdecode_node file_priority = rd.dict_find_list("file_priority");
    		if (file_priority && file_priority.list_size()
    			== files().num_files())
    		{
    			m_file_priority.resize(file_priority.list_size());
    			for (int i = 0; i < file_priority.list_size(); ++i)
    				m_file_priority[i] = boost::uint8_t(file_priority.list_int_value_at(i, 1));
    		}

    		bdecode_node file_sizes_ent = rd.dict_find_list("file sizes");
    		if (file_sizes_ent == 0)
    		{
    			ec.ec = errors::missing_file_sizes;
    			ec.file = -1;
    			ec.operation = storage_error::check_resume;
    			return false;
    		}

    		if (file_sizes_ent.list_size() == 0)

relevance 0 | ../src/storage.cpp:1255 | ideally, if we end up copying files because of a move across volumes, the source should not be deleted until they've all been copied. That would let us rollback with higher confidence.

## ideally, if we end up copying files because of a move across volumes, the source should not be deleted until they've all been copied. That would let us rollback with higher confidence.

#### ../src/storage.cpp:1255

    		std::vector<bool> copied_files(f.num_files(), false);

    		int i;
    		error_code e;
    		for (i = 0; i < f.num_files(); ++i)
    		{
    			// files moved out to absolute paths are not moved
    			if (f.file_absolute_path(i)) continue;

    			std::string const old_path = combine_path(m_save_path, f.file_path(i));
    			std::string const new_path = combine_path(save_path, f.file_path(i));

    			if (flags == dont_replace && exists(new_path))
    			{
    				if (ret == piece_manager::no_error) ret = piece_manager::need_full_check;
    				// this is a new file, clear our cached version
    				m_stat_cache.set_dirty(i);
    				continue;
    			}

    			move_file(old_path, new_path, e);

    			// if the source file doesn't exist. That's not a problem
    			// we just ignore that file
    			if (e == boost::system::errc::no_such_file_or_directory)
    			{
    				e.clear();
    				// the source file doesn't exist, but it may exist at the
    				// destination, we don't know.
    				m_stat_cache.set_dirty(i);
    			}
    			else if (e
    				&& e != boost::system::errc::invalid_argument
    				&& e != boost::system::errc::permission_denied)
    			{
    				// moving the file failed
    				// on OSX, the error when trying to rename a file across different
    				// volumes is EXDEV, which will make it fall back to copying.
    				e.clear();
    				copy_file(old_path, new_path, e);
    				if (!e) copied_files[i] = true;
    			}

    			if (e)
    			{
    				ec.ec = e;
    				ec.file = i;
    				ec.operation = storage_error::rename;
    				break;
    			}
    		}

relevance 0 | ../src/string_util.cpp:60 | warning C4146: unary minus operator applied to unsigned type, result still unsigned

## warning C4146: unary minus operator applied to unsigned type, result still unsigned

#### ../src/string_util.cpp:60

    #include <boost/tuple/tuple.hpp>

    #include <cstdlib> // for malloc
    #include <cstring> // for memmov/strcpy/strlen

    #include "libtorrent/aux_/disable_warnings_pop.hpp"

    namespace libtorrent
    {

    	// lexical_cast's result depends on the locale. We need
    	// a well defined result
    	boost::array<char, 4 + std::numeric_limits<boost::int64_t>::digits10>
    		to_string(boost::int64_t n)
    	{
    		boost::array<char, 4 + std::numeric_limits<boost::int64_t>::digits10> ret;
    		char *p = &ret.back();
    		*p = '\0';
    		boost::uint64_t un = n;
    		if (n < 0)  un = -un;
    		do {
    			*--p = '0' + un % 10;
    			un /= 10;
    		} while (un);
    		if (n < 0) *--p = '-';
    		std::memmove(&ret[0], p, &ret.back() - p + 1);
    		return ret;
    	}

    	bool is_alpha(char c)
    	{
    		return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
    	}

    	bool is_print(char c)
    	{
    		return c >= 32 && c < 127;
    	}

    	bool is_space(char c)
    	{
    		static const char* ws = " \t\n\r\f\v";
    		return strchr(ws, c) != 0;
    	}

    	char to_lower(char c)
    	{
    		return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
    	}

relevance 0 | ../src/torrent.cpp:102 | factor out cache_status to its own header

## factor out cache_status to its own header

#### ../src/torrent.cpp:102

    #include "libtorrent/aux_/session_interface.hpp"
    #include "libtorrent/instantiate_connection.hpp"
    #include "libtorrent/assert.hpp"
    #include "libtorrent/broadcast_socket.hpp"
    #include "libtorrent/kademlia/dht_tracker.hpp"
    #include "libtorrent/peer_info.hpp"
    #include "libtorrent/http_connection.hpp"
    #include "libtorrent/random.hpp"
    #include "libtorrent/peer_class.hpp" // for peer_class
    #include "libtorrent/socket_io.hpp" // for read_*_endpoint
    #include "libtorrent/ip_filter.hpp"
    #include "libtorrent/request_blocks.hpp"
    #include "libtorrent/performance_counters.hpp" // for counters
    #include "libtorrent/resolver_interface.hpp"
    #include "libtorrent/alloca.hpp"
    #include "libtorrent/resolve_links.hpp"
    #include "libtorrent/aux_/file_progress.hpp"
    #include "libtorrent/alert_manager.hpp"
    #include "libtorrent/disk_interface.hpp"
    #include "libtorrent/broadcast_socket.hpp" // for is_ip_address
    #include "libtorrent/disk_io_thread.hpp" // for cache_status

    #ifndef TORRENT_DISABLE_LOGGING
    #include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
    #endif

    using namespace libtorrent;
    using boost::tuples::tuple;
    using boost::tuples::get;
    using boost::tuples::make_tuple;

    namespace libtorrent
    {
    	namespace {

    	int root2(int x)
    	{
    		int ret = 0;
    		x >>= 1;
    		while (x > 0)
    		{
    			// if this assert triggers, the block size
    			// is not an even 2 exponent!
    			TORRENT_ASSERT(x == 1 || (x & 1) == 0);
    			++ret;
    			x >>= 1;
    		}
    		return ret;
    	}

    	} // anonymous namespace

relevance 0 | ../src/torrent.cpp:472 | if the existing torrent doesn't have metadata, insert the metadata we just downloaded into it.

## if the existing torrent doesn't have metadata, insert the metadata we just downloaded into it.

#### ../src/torrent.cpp:472

    		m_torrent_file = tf;

    		// now, we might already have this torrent in the session.
    		boost::shared_ptr<torrent> t = m_ses.find_torrent(m_torrent_file->info_hash()).lock();
    		if (t)
    		{
    			if (!m_uuid.empty() && t->uuid().empty())
    				t->set_uuid(m_uuid);
    			if (!m_url.empty() && t->url().empty())
    				t->set_url(m_url);
    			if (!m_source_feed_url.empty() && t->source_feed_url().empty())
    				t->set_source_feed_url(m_source_feed_url);

    			// insert this torrent in the uuid index
    			if (!m_uuid.empty() || !m_url.empty())
    			{
    				m_ses.insert_uuid_torrent(m_uuid.empty() ? m_url : m_uuid, t);
    			}

    			set_error(errors::duplicate_torrent, error_file_url);
    			abort();
    			return;
    		}

    		m_ses.insert_torrent(m_torrent_file->info_hash(), me, m_uuid);

    		TORRENT_ASSERT(num_torrents == int(m_ses.m_torrents.size()));

    		// if the user added any trackers while downloading the
    		// .torrent file, merge them into the new tracker list
    		std::vector<announce_entry> new_trackers = m_torrent_file->trackers();
    		for (std::vector<announce_entry>::iterator i = m_trackers.begin()
    			, end(m_trackers.end()); i != end; ++i)
    		{
    			// if we already have this tracker, ignore it
    			if (std::find_if(new_trackers.begin(), new_trackers.end()
    				, boost::bind(&announce_entry::url, _1) == i->url) != new_trackers.end())
    				continue;

    			// insert the tracker ordered by tier
    			new_trackers.insert(std::find_if(new_trackers.begin(), new_trackers.end()
    				, boost::bind(&announce_entry::tier, _1) >= i->tier), *i);
    		}
    		m_trackers.swap(new_trackers);

    #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
    		hasher h;
    		h.update("req2", 4);
    		h.update((char*)&m_torrent_file->info_hash()[0], 20);

relevance 0 | ../src/torrent.cpp:584 | if the existing torrent doesn't have metadata, insert the metadata we just downloaded into it.

## if the existing torrent doesn't have metadata, insert the metadata we just downloaded into it.

#### ../src/torrent.cpp:584

    		m_torrent_file = tf;
    		m_info_hash = tf->info_hash();

    		// now, we might already have this torrent in the session.
    		boost::shared_ptr<torrent> t = m_ses.find_torrent(m_torrent_file->info_hash()).lock();
    		if (t)
    		{
    			if (!m_uuid.empty() && t->uuid().empty())
    				t->set_uuid(m_uuid);
    			if (!m_url.empty() && t->url().empty())
    				t->set_url(m_url);
    			if (!m_source_feed_url.empty() && t->source_feed_url().empty())
    				t->set_source_feed_url(m_source_feed_url);

    			// insert this torrent in the uuid index
    			if (!m_uuid.empty() || !m_url.empty())
    			{
    				m_ses.insert_uuid_torrent(m_uuid.empty() ? m_url : m_uuid, t);
    			}

    			set_error(errors::duplicate_torrent, torrent_status::error_file_url);
    			abort();
    			return;
    		}

    		m_ses.insert_torrent(m_torrent_file->info_hash(), me, m_uuid);

    		// if the user added any trackers while downloading the
    		// .torrent file, merge them into the new tracker list
    		std::vector<announce_entry> new_trackers = m_torrent_file->trackers();
    		for (std::vector<announce_entry>::iterator i = m_trackers.begin()
    			, end(m_trackers.end()); i != end; ++i)
    		{
    			// if we already have this tracker, ignore it
    			if (std::find_if(new_trackers.begin(), new_trackers.end()
    				, boost::bind(&announce_entry::url, _1) == i->url) != new_trackers.end())
    				continue;

    			// insert the tracker ordered by tier
    			new_trackers.insert(std::find_if(new_trackers.begin(), new_trackers.end()
    				, boost::bind(&announce_entry::tier, _1) >= i->tier), *i);
    		}
    		m_trackers.swap(new_trackers);

    		// add the web seeds from the .torrent file
    		std::vector<web_seed_entry> const& web_seeds = m_torrent_file->web_seeds();
    		m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end());

    #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
    		hasher h;

relevance 0

../src/torrent.cpp:1595

is verify_peer_cert called once per certificate in the chain, and this function just tells us which depth we're at right now? If so, the comment makes sense. any certificate that isn't the leaf (i.e. the one presented by the peer) should be accepted automatically, given preverified is true. The leaf certificate need to be verified to make sure its DN matches the info-hash

## is verify_peer_cert called once per certificate in the chain, and this function just tells us which depth we're at right now? If so, the comment makes sense. any certificate that isn't the leaf (i.e. the one presented by the peer) should be accepted automatically, given preverified is true. The leaf certificate need to be verified to make sure its DN matches the info-hash

#### ../src/torrent.cpp:1595

    			if (pp) p->add_extension(pp);
    		}

    		// if files are checked for this torrent, call the extension
    		// to let it initialize itself
    		if (m_connections_initialized)
    			tp->on_files_checked();
    	}

    #endif

    #ifdef TORRENT_USE_OPENSSL

    #if BOOST_VERSION >= 104700
    	bool torrent::verify_peer_cert(bool preverified, boost::asio::ssl::verify_context& ctx)
    	{
    		// if the cert wasn't signed by the correct CA, fail the verification
    		if (!preverified) return false;

    		// we're only interested in checking the certificate at the end of the chain.
    		int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
    		if (depth > 0) return true;

    		X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());

    		// Go through the alternate names in the certificate looking for matching DNS entries
    		GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>(
    			X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0));

    #ifndef TORRENT_DISABLE_LOGGING
    		std::string names;
    		bool match = false;
    #endif
    		for (int i = 0; i < aux::openssl_num_general_names(gens); ++i)
    		{
    			GENERAL_NAME* gen = aux::openssl_general_name_value(gens, i);
    			if (gen->type != GEN_DNS) continue;
    			ASN1_IA5STRING* domain = gen->d.dNSName;
    			if (domain->type != V_ASN1_IA5STRING || !domain->data || !domain->length) continue;
    			const char* torrent_name = reinterpret_cast<const char*>(domain->data);
    			std::size_t name_length = domain->length;

    #ifndef TORRENT_DISABLE_LOGGING
    			if (i > 1) names += " | n: ";
    			names.append(torrent_name, name_length);
    #endif
    			if (strncmp(torrent_name, "*", name_length) == 0
    				|| strncmp(torrent_name, m_torrent_file->name().c_str(), name_length) == 0)
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				match = true;

relevance 0 | ../src/torrent.cpp:2021 | instead of creating the picker up front here, maybe this whole section should move to need_picker()

## instead of creating the picker up front here, maybe this whole section should move to need_picker()

#### ../src/torrent.cpp:2021

    			m_ses.get_io_service().post(boost::bind(&torrent::files_checked, shared_from_this()));
    			m_resume_data.reset();
    			update_gauge();
    			update_state_list();
    			return;
    		}

    		set_state(torrent_status::checking_resume_data);

    		int num_pad_files = 0;
    		TORRENT_ASSERT(block_size() > 0);
    		file_storage const& fs = m_torrent_file->files();
    		for (int i = 0; i < fs.num_files(); ++i)
    		{
    			if (!fs.pad_file_at(i) || fs.file_size(i) == 0) continue;

    			if (fs.pad_file_at(i)) ++num_pad_files;

    			m_padding += boost::uint32_t(fs.file_size(i));

    			need_picker();

    			peer_request pr = m_torrent_file->map_file(i, 0, fs.file_size(i));
    			int off = pr.start & (block_size()-1);
    			if (off != 0) { pr.length -= block_size() - off; pr.start += block_size() - off; }
    			TORRENT_ASSERT((pr.start & (block_size()-1)) == 0);

    			int block = block_size();
    			int blocks_per_piece = m_torrent_file->piece_length() / block;
    			piece_block pb(pr.piece, pr.start / block);
    			for (; pr.length >= block; pr.length -= block, ++pb.block_index)
    			{
    				if (int(pb.block_index) == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
    				m_picker->mark_as_finished(pb, 0);
    			}
    			// ugly edge case where padfiles are not used they way they're
    			// supposed to be. i.e. added back-to back or at the end
    			if (pb.block_index == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
    			if (pr.length > 0 && ((i+1 != fs.num_files() && fs.pad_file_at(i+1))
    				|| i + 1 == fs.num_files()))
    			{
    				m_picker->mark_as_finished(pb, 0);
    			}
    		}

    		if (m_padding > 0)
    		{
    			// if we marked an entire piece as finished, we actually
    			// need to consider it finished

    			std::vector<piece_picker::downloading_piece> dq

relevance 0 | ../src/torrent.cpp:2095 | this could be optimized by looking up which files are complete and just look at those

## this could be optimized by looking up which files are complete and just look at those

#### ../src/torrent.cpp:2095

    		if (!need_loaded()) return;

    		if (num_pad_files > 0)
    			m_picker->set_num_pad_files(num_pad_files);

    		std::vector<std::string> links;
    #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
    		if (!m_torrent_file->similar_torrents().empty()
    			|| !m_torrent_file->collections().empty())
    		{
    			resolve_links res(m_torrent_file);

    			std::vector<sha1_hash> s = m_torrent_file->similar_torrents();
    			for (std::vector<sha1_hash>::iterator i = s.begin(), end(s.end());
    				i != end; ++i)
    			{
    				boost::shared_ptr<torrent> t = m_ses.find_torrent(*i).lock();
    				if (!t) continue;

    				// Only attempt to reuse files from torrents that are seeding.
    				if (!t->is_seed()) continue;

    				res.match(t->get_torrent_copy(), t->save_path());
    			}
    			std::vector<std::string> c = m_torrent_file->collections();
    			for (std::vector<std::string>::iterator i = c.begin(), end(c.end());
    				i != end; ++i)
    			{
    				std::vector<boost::shared_ptr<torrent> > ts = m_ses.find_collection(*i);

    				for (std::vector<boost::shared_ptr<torrent> >::iterator k = ts.begin()
    					, end2(ts.end()); k != end2; ++k)
    				{
    					// Only attempt to reuse files from torrents that are seeding.

relevance 0 | ../src/torrent.cpp:2111 | this could be optimized by looking up which files are complete and just look at those

## this could be optimized by looking up which files are complete and just look at those

#### ../src/torrent.cpp:2111

    				i != end; ++i)
    			{
    				boost::shared_ptr<torrent> t = m_ses.find_torrent(*i).lock();
    				if (!t) continue;

    				// Only attempt to reuse files from torrents that are seeding.
    				if (!t->is_seed()) continue;

    				res.match(t->get_torrent_copy(), t->save_path());
    			}
    			std::vector<std::string> c = m_torrent_file->collections();
    			for (std::vector<std::string>::iterator i = c.begin(), end(c.end());
    				i != end; ++i)
    			{
    				std::vector<boost::shared_ptr<torrent> > ts = m_ses.find_collection(*i);

    				for (std::vector<boost::shared_ptr<torrent> >::iterator k = ts.begin()
    					, end2(ts.end()); k != end2; ++k)
    				{
    					// Only attempt to reuse files from torrents that are seeding.
    					if (!(*k)->is_seed()) continue;

    					res.match((*k)->get_torrent_copy(), (*k)->save_path());
    				}
    			}

    			std::vector<resolve_links::link_t> const& l = res.get_links();
    			if (!l.empty())
    			{
    				for (std::vector<resolve_links::link_t>::const_iterator i = l.begin()
    					, end(l.end()); i != end; ++i)
    				{
    					if (!i->ti) continue;

    					torrent_info const& ti = *i->ti;
    					std::string const& save_path = i->save_path;
    					links.push_back(combine_path(save_path
    						, ti.files().file_path(i->file_idx)));
    				}
    			}
    		}
    #endif // TORRENT_DISABLE_MUTABLE_TORRENTS

    		inc_refcount("check_fastresume");
    		// async_check_fastresume will gut links
    		m_ses.disk_thread().async_check_fastresume(
    			m_storage.get(), m_resume_data ? &m_resume_data->node : NULL
    			, links, boost::bind(&torrent::on_resume_data_checked
    			, shared_from_this(), _1));
    #ifndef TORRENT_DISABLE_LOGGING
    		debug_log("init, async_check_fastresume");

relevance 0 | ../src/torrent.cpp:2278 | there may be peer extensions relying on the torrent extension still being alive. Only do this if there are no peers. And when the last peer is disconnected, if the torrent is unloaded, clear the extensions m_extensions.clear();

## there may be peer extensions relying on the torrent extension still being alive. Only do this if there are no peers. And when the last peer is disconnected, if the torrent is unloaded, clear the extensions m_extensions.clear();

#### ../src/torrent.cpp:2278

    		// pinned torrents are not allowed to be swapped out
    		TORRENT_ASSERT(!m_pinned);

    		m_should_be_loaded = false;

    		// make sure it's not unloaded in the middle of some operation that uses it
    		if (m_refcount > 0) return;

    		// call on_unload() on extensions
    #ifndef TORRENT_DISABLE_EXTENSIONS
    		for (extension_list_t::iterator i = m_extensions.begin()
    			, end(m_extensions.end()); i != end; ++i)
    		{
    			TORRENT_TRY {
    				(*i)->on_unload();
    			} TORRENT_CATCH (std::exception&) {}
    		}

    		// also remove extensions and re-instantiate them when the torrent is loaded again
    		// they end up using a significant amount of memory
    #endif

    		// someone else holds a reference to the torrent_info
    		// make the torrent release its reference to it,
    		// after making a copy and then unloading that version
    		// as soon as the user is done with its copy of torrent_info
    		// it will be freed, and we'll have the unloaded version left
    		if (!m_torrent_file.unique())
    			m_torrent_file = boost::make_shared<torrent_info>(*m_torrent_file);

    		m_torrent_file->unload();
    		inc_stats_counter(counters::num_loaded_torrents, -1);

    		m_storage.reset();

    		state_updated();
    	}

    	bt_peer_connection* torrent::find_introducer(tcp::endpoint const& ep) const
    	{
    #ifndef TORRENT_DISABLE_EXTENSIONS
    		for (const_peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
    		{
    			TORRENT_INCREMENT(m_iterating_connections);
    			if ((*i)->type() != peer_connection::bittorrent_connection) continue;
    			bt_peer_connection* p = static_cast<bt_peer_connection*>(*i);
    			if (!p->supports_holepunch()) continue;
    			peer_plugin const* pp = p->find_plugin("ut_pex");
    			if (!pp) continue;
    			if (was_introduced_by(pp, ep)) return p;
    		}

relevance 0 | ../src/torrent.cpp:2994 | this pattern is repeated in a few places. Factor this into a function and generalize the concept of a torrent having a dedicated listen port

## this pattern is repeated in a few places. Factor this into a function and generalize the concept of a torrent having a dedicated listen port

#### ../src/torrent.cpp:2994

    		// if the files haven't been checked yet, we're
    		// not ready for peers. Except, if we don't have metadata,
    		// we need peers to download from
    		if (!m_files_checked && valid_metadata()) return;

    		if (!m_announce_to_lsd) return;

    		// private torrents are never announced on LSD
    		if (m_torrent_file->is_valid() && m_torrent_file->priv()) return;

    		// i2p torrents are also never announced on LSD
    		// unless we allow mixed swarms
    		if (m_torrent_file->is_valid()
    			&& (torrent_file().is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)))
    			return;

    		if (is_paused()) return;

    		if (!m_ses.has_lsd()) return;

    #ifdef TORRENT_USE_OPENSSL
    		int port = is_ssl_torrent() ? m_ses.ssl_listen_port() : m_ses.listen_port();
    #else
    		int port = m_ses.listen_port();
    #endif

    		// announce with the local discovery service
    		m_ses.announce_lsd(m_torrent_file->info_hash(), port
    			, settings().get_bool(settings_pack::broadcast_lsd) && m_lsd_seq == 0);
    		++m_lsd_seq;
    	}

    #ifndef TORRENT_DISABLE_DHT

    	void torrent::dht_announce()
    	{
    		TORRENT_ASSERT(is_single_thread());
    		if (!m_ses.dht())
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			debug_log("DHT: no dht initialized");
    #endif
    			return;
    		}
    		if (!should_announce_dht())
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			if (!m_ses.announce_dht())
    				debug_log("DHT: no listen sockets");

    			if (m_torrent_file->is_valid() && !m_files_checked)

relevance 0 | ../src/torrent.cpp:3859 | add one peer per IP the hostname resolves to

## add one peer per IP the hostname resolves to

#### ../src/torrent.cpp:3859

    #endif

    	void torrent::on_peer_name_lookup(error_code const& e
    		, std::vector<address> const& host_list, int port)
    	{
    		TORRENT_ASSERT(is_single_thread());

    		INVARIANT_CHECK;

    #if defined TORRENT_ASIO_DEBUGGING
    		complete_async("torrent::on_peer_name_lookup");
    #endif

    #ifndef TORRENT_DISABLE_LOGGING
    		if (e)
    			debug_log("peer name lookup error: %s", e.message().c_str());
    #endif

    		if (e || m_abort || host_list.empty() || m_ses.is_aborted()) return;

    		tcp::endpoint host(host_list.front(), port);

    		if (m_ip_filter && m_ip_filter->access(host.address()) & ip_filter::blocked)
    		{
    #ifndef TORRENT_DISABLE_LOGGING
    			error_code ec;
    			debug_log("blocked ip from tracker: %s", host.address().to_string(ec).c_str());
    #endif
    			if (m_ses.alerts().should_post<peer_blocked_alert>())
    				m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
    					, host.address(), peer_blocked_alert::ip_filter);
    			return;
    		}

    		if (add_peer(host, peer_info::tracker))
    			state_updated();
    		update_want_peers();
    	}

    	boost::int64_t torrent::bytes_left() const
    	{
    		// if we don't have the metadata yet, we
    		// cannot tell how big the torrent is.
    		if (!valid_metadata()) return -1;
    		return m_torrent_file->total_size()
    			- quantized_bytes_done();
    	}

    	boost::int64_t torrent::quantized_bytes_done() const
    	{
    //		INVARIANT_CHECK;

relevance 0 | ../src/torrent.cpp:4805 | update suggest_piece?

## update suggest_piece?

#### ../src/torrent.cpp:4805

    		if (has_picker())
    		{
    			torrent_peer* pp = peer->peer_info_struct();
    			m_picker->inc_refcount_all(pp);
    		}
    #ifdef TORRENT_DEBUG
    		else
    		{
    			TORRENT_ASSERT(is_seed() || !m_have_all);
    		}
    #endif
    	}

    	void torrent::peer_lost(bitfield const& bits, peer_connection const* peer)
    	{
    		if (has_picker())
    		{
    			TORRENT_ASSERT(bits.size() == torrent_file().num_pieces());
    			torrent_peer* pp = peer->peer_info_struct();
    			m_picker->dec_refcount(bits, pp);
    		}
    #ifdef TORRENT_DEBUG
    		else
    		{
    			TORRENT_ASSERT(is_seed() || !m_have_all);
    		}
    #endif
    	}

    	void torrent::peer_lost(int index, peer_connection const* peer)
    	{
    		if (m_picker.get())
    		{
    			torrent_peer* pp = peer->peer_info_struct();
    			m_picker->dec_refcount(index, pp);
    			update_suggest_piece(index, -1);
    		}
    #ifdef TORRENT_DEBUG
    		else
    		{
    			TORRENT_ASSERT(is_seed() || !m_have_all);
    		}
    #endif
    	}

    	void torrent::add_suggest_piece(int index)
    	{
    		// it would be nice if we would keep track of piece
    		// availability even when we're a seed, for
    		// the suggest piece feature
    		if (!has_picker()) return;

relevance 0 | ../src/torrent.cpp:4950 | really, we should just keep the picker around in this case to maintain the availability counters

## really, we should just keep the picker around in this case to maintain the availability counters

#### ../src/torrent.cpp:4950

    		pieces.reserve(cs.pieces.size());

    		// sort in ascending order, to get most recently used first
    		std::sort(cs.pieces.begin(), cs.pieces.end()
    			, boost::bind(&cached_piece_info::last_use, _1)
    			> boost::bind(&cached_piece_info::last_use, _2));

    		for (std::vector<cached_piece_info>::iterator i = cs.pieces.begin()
    			, end(cs.pieces.end()); i != end; ++i)
    		{
    			TORRENT_ASSERT(i->storage == m_storage.get());
    			if (!has_piece_passed(i->piece)) continue;
    			suggest_piece_t p;
    			p.piece_index = i->piece;
    			if (has_picker())
    			{
    				p.num_peers = m_picker->get_availability(i->piece);
    			}
    			else
    			{
    				p.num_peers = 0;
    				for (const_peer_iterator j = m_connections.begin()
    					, end2(m_connections.end()); j != end2; ++j)
    				{
    					TORRENT_INCREMENT(m_iterating_connections);
    					peer_connection* peer = *j;
    					if (peer->has_piece(p.piece_index)) ++p.num_peers;
    				}
    			}
    			pieces.push_back(p);
    		}

    		// sort by rarity (stable, to maintain sort
    		// by last use)
    		std::stable_sort(pieces.begin(), pieces.end());

    		// only suggest half of the pieces
    		pieces.resize(pieces.size() / 2);

    		// send new suggests to peers
    		// the peers will filter out pieces we've
    		// already suggested to them
    		for (std::vector<suggest_piece_t>::iterator i = pieces.begin()
    			, end(pieces.end()); i != end; ++i)
    		{
    			for (peer_iterator p = m_connections.begin();
    				p != m_connections.end(); ++p)
    			{
    				TORRENT_INCREMENT(m_iterating_connections);
    				(*p)->send_suggest(i->piece_index);
    			}

relevance 0

../src/torrent.cpp:7039

make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance maybe use the same format as .torrent files and reuse some code from torrent_info The mapped_files needs to be read both in the network thread and in the disk thread, since they both have their own mapped files structures which are kept in sync

## make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance maybe use the same format as .torrent files and reuse some code from torrent_info The mapped_files needs to be read both in the network thread and in the disk thread, since they both have their own mapped files structures which are kept in sync

#### ../src/torrent.cpp:7039

    			{
    				m_save_path = p;
    #ifndef TORRENT_DISABLE_LOGGING
    				debug_log("loaded resume data: save-path: %s", m_save_path.c_str());
    #endif
    			}
    		}

    		m_url = rd.dict_find_string_value("url");
    		m_uuid = rd.dict_find_string_value("uuid");
    		m_source_feed_url = rd.dict_find_string_value("feed");

    		if (!m_uuid.empty() || !m_url.empty())
    		{
    			boost::shared_ptr<torrent> me(shared_from_this());

    			// insert this torrent in the uuid index
    			m_ses.insert_uuid_torrent(m_uuid.empty() ? m_url : m_uuid, me);
    		}

    		bdecode_node mapped_files = rd.dict_find_list("mapped_files");
    		if (mapped_files && mapped_files.list_size() == m_torrent_file->num_files())
    		{
    			for (int i = 0; i < m_torrent_file->num_files(); ++i)
    			{
    				std::string new_filename = mapped_files.list_string_value_at(i);
    				if (new_filename.empty()) continue;
    				m_torrent_file->rename_file(i, new_filename);
    			}
    		}

    		m_added_time = rd.dict_find_int_value("added_time", m_added_time);
    		m_completed_time = rd.dict_find_int_value("completed_time", m_completed_time);
    		if (m_completed_time != 0 && m_completed_time < m_added_time)
    			m_completed_time = m_added_time;

    		if (m_file_priority.empty())
    		{
    			bdecode_node file_priority = rd.dict_find_list("file_priority");
    			if (file_priority)
    			{
    				const int num_files = (std::min)(file_priority.list_size()
    					, m_torrent_file->num_files());
    				m_file_priority.resize(num_files, 4);
    				for (int i = 0; i < num_files; ++i)
    				{
    					m_file_priority[i] = file_priority.list_int_value_at(i, 1);
    					// this is suspicious, leave seed mode
    					if (m_file_priority[i] == 0) m_seed_mode = false;
    				}
    				// unallocated slots are assumed to be priority 1, so cut off any

relevance 0 | ../src/torrent.cpp:7178 | if this is a merkle torrent and we can't restore the tree, we need to wipe all the bits in the have array, but not necessarily we might want to do a full check to see if we have all the pieces. This is low priority since almost no one uses merkle torrents

## if this is a merkle torrent and we can't restore the tree, we need to wipe all the bits in the have array, but not necessarily we might want to do a full check to see if we have all the pieces. This is low priority since almost no one uses merkle torrents

#### ../src/torrent.cpp:7178

    				add_web_seed(url, web_seed_entry::http_seed);
    			}
    		}

    		if (m_torrent_file->is_merkle_torrent())
    		{
    			bdecode_node mt = rd.dict_find_string("merkle tree");
    			if (mt)
    			{
    				std::vector<sha1_hash> tree;
    				tree.resize(m_torrent_file->merkle_tree().size());
    				std::memcpy(&tree[0], mt.string_ptr()
    					, (std::min)(mt.string_length(), int(tree.size()) * 20));
    				if (mt.string_length() < int(tree.size()) * 20)
    					std::memset(&tree[0] + mt.string_length() / 20, 0
    						, tree.size() - mt.string_length() / 20);
    				m_torrent_file->set_merkle_tree(tree);
    			}
    			else
    			{
    				TORRENT_ASSERT(false);
    			}
    		}

    		// updating some of the torrent state may have set need_save_resume_data.
    		// clear it here since we've just restored the resume data we already
    		// have. Nothing has changed from that state yet.
    		m_need_save_resume_data = false;

    		if (m_seed_mode)
    		{
    			// some sanity checking. Maybe we shouldn't be in seed mode anymore
    			bdecode_node pieces = rd.dict_find("pieces");
    			if (pieces && pieces.type() == bdecode_node::string_t
    				&& pieces.string_length() == m_torrent_file->num_pieces())
    			{
    				char const* pieces_str = pieces.string_ptr();
    				for (int i = 0, end(pieces.string_length()); i < end; ++i)
    				{
    					// being in seed mode and missing a piece is not compatible.
    					// Leave seed mode if that happens
    					if ((pieces_str[i] & 1)) continue;
    					m_seed_mode = false;
    					break;
    				}
    			}

    			bdecode_node piece_priority = rd.dict_find_string("piece_priority");
    			if (piece_priority && piece_priority.string_length()
    				== m_torrent_file->num_pieces())
    			{

relevance 0

../src/torrent.cpp:7279

re-enable this code once there's a non-inlined encoder function. Or perhaps this should not be used until saving resume_data via add_torrent_params and a free function, similar to read_resume_data boost::shared_array<char> const info = torrent_file().metadata(); int const size = torrent_file().metadata_size(); ret["info"].preformatted().assign(&info[0], &info[0] + size);

## re-enable this code once there's a non-inlined encoder function. Or perhaps this should not be used until saving resume_data via add_torrent_params and a free function, similar to read_resume_data boost::shared_array<char> const info = torrent_file().metadata(); int const size = torrent_file().metadata_size(); ret["info"].preformatted().assign(&info[0], &info[0] + size);

#### ../src/torrent.cpp:7279

    		ret["super_seeding"] = m_super_seeding;

    		ret["added_time"] = m_added_time;
    		ret["completed_time"] = m_completed_time;

    		ret["save_path"] = m_save_path;

    		if (!m_url.empty()) ret["url"] = m_url;
    		if (!m_uuid.empty()) ret["uuid"] = m_uuid;
    		if (!m_source_feed_url.empty()) ret["feed"] = m_source_feed_url;

    		const sha1_hash& info_hash = torrent_file().info_hash();
    		ret["info-hash"] = info_hash.to_string();

    		if (valid_metadata())
    		{
    			if (m_magnet_link || (m_save_resume_flags & torrent_handle::save_info_dict))
    			{
    				ret["info"] = bdecode(&torrent_file().metadata()[0]
    					, &torrent_file().metadata()[0] + torrent_file().metadata_size());
    			}
    		}

    		// blocks per piece
    		int num_blocks_per_piece =
    			static_cast<int>(torrent_file().piece_length()) / block_size();
    		ret["blocks per piece"] = num_blocks_per_piece;

    		if (m_torrent_file->is_merkle_torrent())
    		{
    			// we need to save the whole merkle hash tree
    			// in order to resume
    			std::string& tree_str = ret["merkle tree"].string();
    			std::vector<sha1_hash> const& tree = m_torrent_file->merkle_tree();
    			tree_str.resize(tree.size() * 20);
    			std::memcpy(&tree_str[0], &tree[0], tree.size() * 20);
    		}

    		// if this torrent is a seed, we won't have a piece picker
    		// if we don't have anything, we may also not have a picker
    		// in either case; there will be no half-finished pieces.
    		if (has_picker())
    		{
    			std::vector<piece_picker::downloading_piece> q
    				= m_picker->get_download_queue();

    			// unfinished pieces
    			ret["unfinished"] = entry::list_type();
    			entry::list_type& up = ret["unfinished"].list();

    			// info for each unfinished piece

relevance 0 | ../src/torrent.cpp:7428 | make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance. using file_base

## make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance. using file_base

#### ../src/torrent.cpp:7428

    			if (!has_picker())
    			{
    				std::memset(&pieces[0], m_have_all, pieces.size());
    			}
    			else if (has_picker())
    			{
    				for (int i = 0, end(pieces.size()); i < end; ++i)
    					pieces[i] = m_picker->have_piece(i) ? 1 : 0;
    			}

    			if (m_seed_mode)
    			{
    				TORRENT_ASSERT(m_verified.size() == pieces.size());
    				TORRENT_ASSERT(m_verifying.size() == pieces.size());
    				for (int i = 0, end(pieces.size()); i < end; ++i)
    					pieces[i] |= m_verified[i] ? 2 : 0;
    			}
    		}

    		// write renamed files
    		if (&m_torrent_file->files() != &m_torrent_file->orig_files()
    			&& m_torrent_file->files().num_files() == m_torrent_file->orig_files().num_files())
    		{
    			entry::list_type& fl = ret["mapped_files"].list();
    			file_storage const& fs = m_torrent_file->files();
    			for (int i = 0; i < fs.num_files(); ++i)
    			{
    				fl.push_back(fs.file_path(i));
    			}
    		}

    		// write local peers

    		std::back_insert_iterator<entry::string_type> peers(ret["peers"].string());
    		std::back_insert_iterator<entry::string_type> banned_peers(ret["banned_peers"].string());
    #if TORRENT_USE_IPV6
    		std::back_insert_iterator<entry::string_type> peers6(ret["peers6"].string());
    		std::back_insert_iterator<entry::string_type> banned_peers6(ret["banned_peers6"].string());
    #endif

    		int num_saved_peers = 0;

    		std::vector<torrent_peer const*> deferred_peers;

    		if (m_peer_list)
    		{
    			for (peer_list::const_iterator i = m_peer_list->begin_peer()
    				, end(m_peer_list->end_peer()); i != end; ++i)
    			{
    				error_code ec;
    				torrent_peer const* p = *i;

relevance 0 | ../src/torrent.cpp:9727 | add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata just to save an empty resume data file

## add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata just to save an empty resume data file

#### ../src/torrent.cpp:9727

    		if (m_complete != 0xffffff) seeds = m_complete;
    		else seeds = m_peer_list ? m_peer_list->num_seeds() : 0;

    		if (m_incomplete != 0xffffff) downloaders = m_incomplete;
    		else downloaders = m_peer_list ? m_peer_list->num_peers() - m_peer_list->num_seeds() : 0;

    		if (seeds == 0)
    		{
    			ret |= no_seeds;
    			ret |= downloaders & prio_mask;
    		}
    		else
    		{
    			ret |= ((1 + downloaders) * scale / seeds) & prio_mask;
    		}

    		return ret;
    	}

    	// this is an async operation triggered by the client
    	void torrent::save_resume_data(int flags)
    	{
    		TORRENT_ASSERT(is_single_thread());
    		INVARIANT_CHECK;

    		if (!valid_metadata())
    		{
    			alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    				, errors::no_metadata);
    			return;
    		}

    		if ((flags & torrent_handle::only_if_modified) && !m_need_save_resume_data)
    		{
    			alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    				, errors::resume_data_not_modified);
    			return;
    		}

    		m_need_save_resume_data = false;
    		m_last_saved_resume = m_ses.session_time();
    		m_save_resume_flags = boost::uint8_t(flags);
    		state_updated();

    		if (m_state == torrent_status::checking_files
    			|| m_state == torrent_status::checking_resume_data)
    		{
    			if (!need_loaded())
    			{
    				alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    					, m_error);

relevance 0 | ../src/torrent.cpp:11391 | instead of resorting the whole list, insert the peers directly into the right place

## instead of resorting the whole list, insert the peers directly into the right place

#### ../src/torrent.cpp:11391

    				printf("timed out [average-piece-time: %d ms ]\n"
    					, m_average_piece_time);
    #endif
    			}

    			// pick all blocks for this piece. the peers list is kept up to date
    			// and sorted. when we issue a request to a peer, its download queue
    			// time will increase and it may need to be bumped in the peers list,
    			// since it's ordered by download queue time
    			pick_time_critical_block(peers, ignore_peers
    				, peers_with_requests
    				, pi, &*i, m_picker.get()
    				, blocks_in_piece, timed_out);

    			// put back the peers we ignored into the peer list for the next piece
    			if (!ignore_peers.empty())
    			{
    				peers.insert(peers.begin(), ignore_peers.begin(), ignore_peers.end());
    				ignore_peers.clear();

    				std::sort(peers.begin(), peers.end()
    					, boost::bind(&peer_connection::download_queue_time, _1, 16*1024)
    					< boost::bind(&peer_connection::download_queue_time, _2, 16*1024));
    			}

    			// if this peer's download time exceeds 2 seconds, we're done.
    			// We don't want to build unreasonably long request queues
    			if (!peers.empty() && peers[0]->download_queue_time() > milliseconds(2000))
    				break;
    		}

    		// commit all the time critical requests
    		for (std::set<peer_connection*>::iterator i = peers_with_requests.begin()
    			, end(peers_with_requests.end()); i != end; ++i)
    		{
    			(*i)->send_block_requests();
    		}
    	}

    	std::set<std::string> torrent::web_seeds(web_seed_entry::type_t type) const
    	{
    		TORRENT_ASSERT(is_single_thread());
    		std::set<std::string> ret;
    		for (std::list<web_seed_t>::const_iterator i = m_web_seeds.begin()
    			, end(m_web_seeds.end()); i != end; ++i)
    		{
    			if (i->peer_info.banned) continue;
    			if (i->removed) continue;
    			if (i->type != type) continue;
    			ret.insert(i->url);
    		}

relevance 0 | ../src/torrent_peer.cpp:188 | how do we deal with our external address changing?

## how do we deal with our external address changing?

#### ../src/torrent_peer.cpp:188

    		, is_v6_addr(false)
    #endif
    #if TORRENT_USE_I2P
    		, is_i2p_addr(false)
    #endif
    		, on_parole(false)
    		, banned(false)
    		, supports_utp(true) // assume peers support utp
    		, confirmed_supports_utp(false)
    		, supports_holepunch(false)
    		, web_seed(false)
    #if TORRENT_USE_ASSERTS
    		, in_use(false)
    #endif
    	{
    		TORRENT_ASSERT((src & 0xff) == src);
    	}

    	boost::uint32_t torrent_peer::rank(external_ip const& external, int external_port) const
    	{
    		if (peer_rank == 0)
    			peer_rank = peer_priority(
    				tcp::endpoint(external.external_address(this->address()), external_port)
    				, tcp::endpoint(this->address(), this->port));
    		return peer_rank;
    	}

    #ifndef TORRENT_DISABLE_LOGGING
    	std::string torrent_peer::to_string() const
    	{
    #if TORRENT_USE_I2P
    		if (is_i2p_addr) return dest();
    #endif // TORRENT_USE_I2P
    		error_code ec;
    		return address().to_string(ec);
    	}
    #endif

    	boost::uint64_t torrent_peer::total_download() const
    	{
    		if (connection != 0)
    		{
    			TORRENT_ASSERT(prev_amount_download == 0);
    			return connection->statistics().total_payload_download();
    		}
    		else
    		{
    			return boost::uint64_t(prev_amount_download) << 10;
    		}
    	}

relevance 0 | ../src/udp_socket.cpp:330 | it would be nice to detect this on posix systems also

## it would be nice to detect this on posix systems also

#### ../src/udp_socket.cpp:330

    				--m_restart_v4;
    				setup_read(s);
    			}
    		}
    		return;
    	}
    	if (m_abort)
    	{
    		close_impl();
    		return;
    	}

    	CHECK_MAGIC;

    	for (;;)
    	{
    		error_code err;
    		udp::endpoint ep;
    		size_t bytes_transferred = s->receive_from(boost::asio::buffer(m_buf, m_buf_size), ep, 0, err);

    #ifdef TORRENT_WINDOWS
    		if ((err == error_code(ERROR_MORE_DATA, system_category())
    			|| err == error_code(WSAEMSGSIZE, system_category()))
    			&& m_buf_size < 65536)
    		{
    			// if this function fails to allocate memory, m_buf_size
    			// is set to 0. In that case, don't issue the async_read().
    			set_buf_size(m_buf_size * 2);
    			if (m_buf_size == 0) return;
    			continue;
    		}
    #endif

    		if (err == boost::asio::error::would_block || err == boost::asio::error::try_again) break;
    		on_read_impl(ep, err, bytes_transferred);

    		// found on iOS, socket will be disconnected when app goes backgroud. try to reopen it.
    		if (err == boost::asio::error::not_connected || err == boost::asio::error::bad_descriptor)
    		{
    			ep = s->local_endpoint(err);
    			if (!err) {
    				bind(ep, err);
    			}
    			return;
    		}
    	}
    	call_drained_handler();
    	setup_read(s);
    }

    void udp_socket::call_handler(error_code const& ec, udp::endpoint const& ep, char const* buf, int size)

relevance 0 | ../src/udp_socket.cpp:884 | use the system resolver_interface here

## use the system resolver_interface here

#### ../src/udp_socket.cpp:884

    	TORRENT_ASSERT(is_single_thread());

    	error_code ec;
    	m_socks5_sock.close(ec);
    	m_tunnel_packets = false;

    	m_proxy_settings = ps;

    	if (m_abort)
    	{
    		close_impl();
    		return;
    	}

    	if (ps.type == settings_pack::socks5
    		|| ps.type == settings_pack::socks5_pw)
    	{
    		m_queue_packets = true;
    		// connect to socks5 server and open up the UDP tunnel

    		tcp::resolver::query q(ps.hostname, to_string(ps.port).elems);
    		++m_outstanding_ops;
    #if TORRENT_USE_ASSERTS
    		++m_outstanding_resolve;
    #endif
    #if defined TORRENT_ASIO_DEBUGGING
    		add_outstanding_async("udp_socket::on_name_lookup");
    #endif
    		m_resolver.async_resolve(q, boost::bind(
    			&udp_socket::on_name_lookup, this, _1, _2));
    	}
    }

    void udp_socket::close_impl()
    {
    	if (m_outstanding_ops == 0)
    	{
    		error_code ec;
    		m_ipv4_sock.close(ec);
    #if TORRENT_USE_IPV6
    		m_ipv6_sock.close(ec);
    #endif
    		m_socks5_sock.close(ec);
    	}
    }

    void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
    {
    #if defined TORRENT_ASIO_DEBUGGING
    	complete_async("udp_socket::on_name_lookup");
    #endif

relevance 0 | ../src/ut_metadata.cpp:320 | we really need to increment the refcounter on the torrent while this buffer is still in the peer's send buffer

## we really need to increment the refcounter on the torrent while this buffer is still in the peer's send buffer

#### ../src/ut_metadata.cpp:320

    				if (!m_tp.need_loaded()) return;
    				metadata = m_tp.metadata().begin + offset;
    				metadata_piece_size = (std::min)(
    					int(m_tp.get_metadata_size() - offset), 16 * 1024);
    				TORRENT_ASSERT(metadata_piece_size > 0);
    				TORRENT_ASSERT(offset >= 0);
    				TORRENT_ASSERT(offset + metadata_piece_size <= int(m_tp.get_metadata_size()));
    			}

    			char msg[200];
    			char* header = msg;
    			char* p = &msg[6];
    			int len = bencode(p, e);
    			int total_size = 2 + len + metadata_piece_size;
    			namespace io = detail;
    			io::write_uint32(total_size, header);
    			io::write_uint8(bt_peer_connection::msg_extended, header);
    			io::write_uint8(m_message_index, header);

    			m_pc.send_buffer(msg, len + 6);
    			if (metadata_piece_size) m_pc.append_const_send_buffer(
    				metadata, metadata_piece_size);

    			m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_extended);
    			m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_metadata);
    		}

    		virtual bool on_extended(int length
    			, int extended_msg, buffer::const_interval body) TORRENT_OVERRIDE
    		{
    			if (extended_msg != 2) return false;
    			if (m_message_index == 0) return false;

    			if (length > 17 * 1024)
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"
    					, "packet too big %d", length);
    #endif
    				m_pc.disconnect(errors::invalid_metadata_message, op_bittorrent, 2);
    				return true;
    			}

    			if (!m_pc.packet_finished()) return true;

    			int len;
    			entry msg = bdecode(body.begin, body.end, len);
    			if (msg.type() != entry::dictionary_t)
    			{
    #ifndef TORRENT_DISABLE_LOGGING
    				m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"

relevance 0 | ../src/utp_stream.cpp:1769 | this loop is not very efficient. It could be fixed by having a separate list of sequence numbers that need resending

## this loop is not very efficient. It could be fixed by having a separate list of sequence numbers that need resending

#### ../src/utp_stream.cpp:1769

    };

    // sends a packet, pulls data from the write buffer (if there's any)
    // if ack is true, we need to send a packet regardless of if there's
    // any data. Returns true if we could send more data (i.e. call
    // send_pkt() again)
    // returns true if there is more space for payload in our
    // congestion window, false if there is no more space.
    bool utp_socket_impl::send_pkt(int const flags)
    {
    #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
    	INVARIANT_CHECK;
    #endif

    	bool const force = (flags & pkt_ack) || (flags & pkt_fin);

    //	TORRENT_ASSERT(m_state != UTP_STATE_FIN_SENT || (flags & pkt_ack));

    	// first see if we need to resend any packets

    	for (int i = (m_acked_seq_nr + 1) & ACK_MASK; i != m_seq_nr; i = (i + 1) & ACK_MASK)
    	{
    		packet* p = m_outbuf.at(i);
    		if (!p) continue;
    		if (!p->need_resend) continue;
    		if (!resend_packet(p))
    		{
    			// we couldn't resend the packet. It probably doesn't
    			// fit in our cwnd. If force is set, we need to continue
    			// to send our packet anyway, if we don't have force set,
    			// we might as well return
    			if (!force) return false;
    			// resend_packet might have failed
    			if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return false;
    			break;
    		}

    		// don't fast-resend this packet
    		if (m_fast_resend_seq_nr == i)
    			m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK;
    	}

    	int sack = 0;
    	if (m_inbuf.size())
    	{
    		// the SACK bitfield should ideally fit all
    		// the pieces we have successfully received
    		sack = (m_inbuf.span() + 7) / 8;
    		if (sack > 32) sack = 32;
    	}

relevance 0 | ../src/web_connection_base.cpp:83 | introduce a web-seed default class which has a low download priority

## introduce a web-seed default class which has a low download priority

#### ../src/web_connection_base.cpp:83

    		: peer_connection(pack)
    		, m_first_request(true)
    		, m_ssl(false)
    		, m_external_auth(web.auth)
    		, m_extra_headers(web.extra_headers)
    		, m_parser(http_parser::dont_parse_chunks)
    		, m_body_start(0)
    	{
    		TORRENT_ASSERT(&web.peer_info == pack.peerinfo);
    		// when going through a proxy, we don't necessarily have an endpoint here,
    		// since the proxy might be resolving the hostname, not us
    		TORRENT_ASSERT(web.endpoints.empty() || web.endpoints.front() == pack.endp);

    		INVARIANT_CHECK;

    		TORRENT_ASSERT(is_outgoing());

    		TORRENT_ASSERT(!m_torrent.lock()->is_upload_only());

    		// we only want left-over bandwidth

    		std::string protocol;
    		error_code ec;
    		boost::tie(protocol, m_basic_auth, m_host, m_port, m_path)
    			= parse_url_components(web.url, ec);
    		TORRENT_ASSERT(!ec);

    		if (m_port == -1 && protocol == "http")
    			m_port = 80;

    #ifdef TORRENT_USE_OPENSSL
    		if (protocol == "https")
    		{
    			m_ssl = true;
    			if (m_port == -1) m_port = 443;
    		}
    #endif

    		if (!m_basic_auth.empty())
    			m_basic_auth = base64encode(m_basic_auth);

    		m_server_string = "URL seed @ ";
    		m_server_string += m_host;
    	}

    	int web_connection_base::timeout() const
    	{
    		// since this is a web seed, change the timeout
    		// according to the settings.
    		return m_settings.get_int(settings_pack::urlseed_timeout);
    	}

relevance 0 | ../src/kademlia/dht_storage.cpp:447 | c++11 use a lambda here instead

## c++11 use a lambda here instead

#### ../src/kademlia/dht_storage.cpp:447

    			return true;
    		}

    		void put_mutable_item(sha1_hash const& target
    			, char const* buf, int size
    			, char const* sig
    			, boost::int64_t seq
    			, char const* pk
    			, char const* salt, int salt_size
    			, address const& addr) TORRENT_OVERRIDE
    		{
    			dht_mutable_table_t::iterator i = m_mutable_table.find(target);
    			if (i == m_mutable_table.end())
    			{
    				// this is the case where we don't have an item in this slot
    				// make sure we don't add too many items
    				if (int(m_mutable_table.size()) >= m_settings.max_dht_items)
    				{
    					// delete the least important one (i.e. the one
    					// the fewest peers are announcing)
    					dht_mutable_table_t::iterator j = std::min_element(m_mutable_table.begin()
    						, m_mutable_table.end()
    						, boost::bind(&dht_immutable_item::num_announcers
    							, boost::bind(&dht_mutable_table_t::value_type::second, _1))
    						< boost::bind(&dht_immutable_item::num_announcers
    							, boost::bind(&dht_mutable_table_t::value_type::second, _2)));
    					TORRENT_ASSERT(j != m_mutable_table.end());
    					std::free(j->second.value);
    					std::free(j->second.salt);
    					m_mutable_table.erase(j);
    					m_counters.mutable_data -= 1;
    				}
    				dht_mutable_item to_add;
    				to_add.value = static_cast<char*>(std::malloc(size));
    				to_add.size = size;
    				to_add.seq = seq;
    				to_add.salt = NULL;
    				to_add.salt_size = 0;
    				if (salt_size > 0)
    				{
    					to_add.salt = static_cast<char*>(std::malloc(salt_size));
    					to_add.salt_size = salt_size;
    					memcpy(to_add.salt, salt, salt_size);
    				}
    				memcpy(to_add.sig, sig, sizeof(to_add.sig));
    				memcpy(to_add.value, buf, size);
    				memcpy(&to_add.key, pk, sizeof(to_add.key));

    				boost::tie(i, boost::tuples::ignore) = m_mutable_table.insert(
    					std::make_pair(target, to_add));
    				m_counters.mutable_data += 1;

relevance 0 | ../src/kademlia/node.cpp:720 | in the future, this function should update all the dht related counter. For now, it just update the storage related ones.

## in the future, this function should update all the dht related counter. For now, it just update the storage related ones.

#### ../src/kademlia/node.cpp:720

    	return d;
    }

    void node::status(std::vector<dht_routing_bucket>& table
    	, std::vector<dht_lookup>& requests)
    {
    	mutex_t::scoped_lock l(m_mutex);

    	m_table.status(table);

    	for (std::set<traversal_algorithm*>::iterator i = m_running_requests.begin()
    		, end(m_running_requests.end()); i != end; ++i)
    	{
    		requests.push_back(dht_lookup());
    		dht_lookup& lookup = requests.back();
    		(*i)->status(lookup);
    	}
    }

    void node::update_stats_counters(counters& c) const
    {
    	const dht_storage_counters& dht_cnt = m_storage->counters();
    	c.set_value(counters::dht_torrents, dht_cnt.torrents);
    	c.set_value(counters::dht_peers, dht_cnt.peers);
    	c.set_value(counters::dht_immutable_data, dht_cnt.immutable_data);
    	c.set_value(counters::dht_mutable_data, dht_cnt.mutable_data);

    	int nodes, replacements;
    	boost::tie(nodes, replacements, boost::tuples::ignore) = size();
    	c.set_value(counters::dht_nodes, nodes);
    	c.set_value(counters::dht_node_cache, replacements);
    	c.set_value(counters::dht_allocated_observers, m_rpc.num_allocated_observers());
    }

    #ifndef TORRENT_NO_DEPRECATE

relevance 0 | ../src/kademlia/put_data.cpp:93 | what if o is not an isntance of put_data_observer? This need to be redesigned for better type saftey.

## what if o is not an isntance of put_data_observer? This need to be redesigned for better type saftey.

#### ../src/kademlia/put_data.cpp:93

    	}
    }

    void put_data::done()
    {
    	m_done = true;

    #ifndef TORRENT_DISABLE_LOGGING
    	get_node().observer()->log(dht_logger::traversal, "[%p] %s DONE, response %d, timeout %d"
    		, static_cast<void*>(this), name(), m_responses, m_timeouts);
    #endif

    	m_put_callback(m_data, m_responses);
    	traversal_algorithm::done();
    }

    bool put_data::invoke(observer_ptr o)
    {
    	if (m_done) return false;

    	put_data_observer* po = static_cast<put_data_observer*>(o.get());

    	entry e;
    	e["y"] = "q";
    	e["q"] = "put";
    	entry& a = e["a"];
    	a["v"] = m_data.value();
    	a["token"] = po->m_token;
    	if (m_data.is_mutable())
    	{
    		a["k"] = std::string(m_data.pk().data(), item_pk_len);
    		a["seq"] = m_data.seq();
    		a["sig"] = std::string(m_data.sig().data(), item_sig_len);
    		if (!m_data.salt().empty())
    		{
    			a["salt"] = m_data.salt();
    		}
    	}

    	return m_node.m_rpc.invoke(e, o->target_ep(), o);
    }

    } } // namespace libtorrent::dht

relevance 0 | ../include/libtorrent/alert_types.hpp:171 | Once the backwards compatibility of clone() is removed, and once C++11 is required, this can be simplified to just say = delete

## Once the backwards compatibility of clone() is removed, and once C++11 is required, this can be simplified to just say = delete

#### ../include/libtorrent/alert_types.hpp:171

    		// The tracker URL
    		std::string TORRENT_DEPRECATED_MEMBER url;
    #endif
    	private:
    		int m_url_idx;
    	};

    #ifndef TORRENT_NO_DEPRECATE
    	#define TORRENT_CLONE(name) \
    		virtual std::auto_ptr<alert> clone_impl() const TORRENT_OVERRIDE \
    		{ return std::auto_ptr<alert>(new name(*this)); }
    #else
    	#define TORRENT_CLONE(name)
    #endif

    	// we can only use = default in C++11
    	// the purpose of this is just to make all alert types non-copyable from user
    	// code. The heterogeneous queue does not yet have an emplace_back(), so it
    	// still needs to copy alerts, but the important part is that it's not
    	// copyable for clients.
    #if __cplusplus >= 201103L
    	#define TORRENT_PROTECTED_CCTOR(name) \
    	protected: \
    		template <class T> friend struct heterogeneous_queue; \
    		name(name const&) = default; \
    	public:
    #else
    	#define TORRENT_PROTECTED_CCTOR(name)
    #endif

    #define TORRENT_DEFINE_ALERT_IMPL(name, seq, prio) \
    	TORRENT_PROTECTED_CCTOR(name) \
    	static const int priority = prio; \
    	static const int alert_type = seq; \
    	virtual int type() const TORRENT_OVERRIDE { return alert_type; } \
    	TORRENT_CLONE(name) \
    	virtual int category() const TORRENT_OVERRIDE { return static_category; } \
    	virtual char const* what() const TORRENT_OVERRIDE { return #name; }

    #define TORRENT_DEFINE_ALERT(name, seq) \
    	TORRENT_DEFINE_ALERT_IMPL(name, seq, 0)

    #define TORRENT_DEFINE_ALERT_PRIO(name, seq) \
    	TORRENT_DEFINE_ALERT_IMPL(name, seq, 1)

    #ifndef TORRENT_NO_DEPRECATE
    	// The ``torrent_added_alert`` is posted once every time a torrent is successfully
    	// added. It doesn't contain any members of its own, but inherits the torrent handle
    	// from its base class.
    	// It's posted when the ``status_notification`` bit is set in the alert_mask.
    	// deprecated in 1.1.3

relevance 0 | ../include/libtorrent/announce_entry.hpp:97 | include the number of peers received from this tracker, at last announce

## include the number of peers received from this tracker, at last announce

#### ../include/libtorrent/announce_entry.hpp:97

    		// if this tracker failed the last time it was contacted
    		// this error code specifies what error occurred
    		error_code last_error;

    		// returns the number of seconds to the next announce on this tracker.
    		// ``min_announce_in()`` returns the number of seconds until we are
    		// allowed to force another tracker update with this tracker.
    		//
    		// If the last time this tracker was contacted failed, ``last_error`` is
    		// the error code describing what error occurred.
    		int next_announce_in() const;
    		int min_announce_in() const;

    		// the time of next tracker announce
    		time_point next_announce;

    		// no announces before this time
    		time_point min_announce;

    		// these are either -1 or the scrape information this tracker last
    		// responded with. *incomplete* is the current number of downloaders in
    		// the swarm, *complete* is the current number of seeds in the swarm and
    		// *downloaded* is the cumulative number of completed downloads of this
    		// torrent, since the beginning of time (from this tracker's point of
    		// view).

    		// if this tracker has returned scrape data, these fields are filled in
    		// with valid numbers. Otherwise they are set to -1. the number of
    		// current downloaders
    		int scrape_incomplete;
    		int scrape_complete;
    		int scrape_downloaded;

    		// the tier this tracker belongs to
    		boost::uint8_t tier;

    		// the max number of failures to announce to this tracker in
    		// a row, before this tracker is not used anymore. 0 means unlimited
    		boost::uint8_t fail_limit;

    		// the number of times in a row we have failed to announce to this
    		// tracker.
    		boost::uint8_t fails:7;

    		// true while we're waiting for a response from the tracker.
    		bool updating:1;

    		// flags for the source bitmask, each indicating where
    		// we heard about this tracker

relevance 0 | ../include/libtorrent/block_cache.hpp:222 | make this 32 bits and to count seconds since the block cache was created

## make this 32 bits and to count seconds since the block cache was created

#### ../include/libtorrent/block_cache.hpp:222

    		bool operator==(cached_piece_entry const& rhs) const
    		{ return storage.get() == rhs.storage.get() && piece == rhs.piece; }

    		// if this is set, we'll be calculating the hash
    		// for this piece. This member stores the interim
    		// state while we're calculating the hash.
    		partial_hash* hash;

    		// set to a unique identifier of a peer that last
    		// requested from this piece.
    		void* last_requester;

    		// the pointers to the block data. If this is a ghost
    		// cache entry, there won't be any data here
    		boost::shared_array<cached_block_entry> blocks;

    		// the last time a block was written to this piece
    		// plus the minimum amount of time the block is guaranteed
    		// to stay in the cache
    		time_point expire;

    		boost::uint64_t piece:22;

    		// the number of dirty blocks in this piece
    		boost::uint64_t num_dirty:14;

    		// the number of blocks in the cache for this piece
    		boost::uint64_t num_blocks:14;

    		// the total number of blocks in this piece (and the number
    		// of elements in the blocks array)
    		boost::uint64_t blocks_in_piece:14;

    		// ---- 64 bit boundary ----

    		// while we have an outstanding async hash operation
    		// working on this piece, 'hashing' is set to 1
    		// When the operation returns, this is set to 0.
    		boost::uint32_t hashing:1;

    		// if we've completed at least one hash job on this
    		// piece, and returned it. This is set to one
    		boost::uint32_t hashing_done:1;

    		// if this is true, whenever refcount hits 0,
    		// this piece should be deleted from the cache
    		// (not just demoted)
    		boost::uint32_t marked_for_deletion:1;

    		// this is set to true once we flush blocks past

relevance 0 | ../include/libtorrent/config.hpp:100 | figure out which version of clang this is supported in

## figure out which version of clang this is supported in

#### ../include/libtorrent/config.hpp:100

    #if defined _MSC_VER || defined __MINGW32__
    #define PRId64 "I64d"
    #define PRIu64 "I64u"
    #define PRIx64 "I64x"
    #define PRIu32 "u"
    #else
    #define PRId64 "lld"
    #define PRIu64 "llu"
    #define PRIx64 "llx"
    #define PRIu32 "u"
    #endif
    #endif

    #include "libtorrent/aux_/disable_warnings_pop.hpp"

    // ====== CLANG ========

    #if defined __clang__

    # if !defined TORRENT_BUILDING_LIBRARY
    #  define TORRENT_DEPRECATED_ENUM __attribute__ ((deprecated))
    #  define TORRENT_DEPRECATED_MEMBER __attribute__ ((deprecated))
    # endif

    // ======= GCC =========

    #elif defined __GNUC__

    // deprecation markup is only enabled when libtorrent
    // headers are included by clients, not while building
    // libtorrent itself
    # if __GNUC__ >= 3 && !defined TORRENT_BUILDING_LIBRARY
    #  define TORRENT_DEPRECATED __attribute__ ((deprecated))
    # endif

    # if __GNUC__ >= 6 && !defined TORRENT_BUILDING_LIBRARY
    #  define TORRENT_DEPRECATED_ENUM __attribute__ ((deprecated))
    #  define TORRENT_DEPRECATED_MEMBER __attribute__ ((deprecated))
    # endif

    // ======= SUNPRO =========

    #elif defined __SUNPRO_CC

    // SunPRO seems to have an overly-strict
    // definition of POD types and doesn't
    // seem to allow boost::array in unions
    #define TORRENT_BROKEN_UNIONS 1

    // ======= MSVC =========

relevance 0 | ../include/libtorrent/config.hpp:366 | Make this count Unicode characters instead of bytes on windows

## Make this count Unicode characters instead of bytes on windows

#### ../include/libtorrent/config.hpp:366

    #pragma message ( "unknown OS, assuming BSD" )
    #else
    #warning "unknown OS, assuming BSD"
    #endif

    #define TORRENT_BSD
    #endif

    #if defined __GNUC__ && !(defined TORRENT_USE_OSATOMIC \
    	|| defined TORRENT_USE_INTERLOCKED_ATOMIC \
    	|| defined TORRENT_USE_BEOS_ATOMIC \
    	|| defined TORRENT_USE_SOLARIS_ATOMIC)
    // atomic operations in GCC were introduced in 4.1.1
    # if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 1) || __GNUC__ > 4
    #  define TORRENT_USE_GCC_ATOMIC 1
    # endif
    #endif

    // on windows, NAME_MAX refers to Unicode characters
    // on linux it refers to bytes (utf-8 encoded)

    // windows
    #if defined FILENAME_MAX
    #define TORRENT_MAX_PATH FILENAME_MAX

    // beos
    #elif defined B_PATH_NAME_LENGTH
    #define TORRENT_MAX_PATH B_PATH_NAME_LENGTH

    // solaris
    #elif defined MAXPATH
    #define TORRENT_MAX_PATH MAXPATH

    // none of the above
    #else
    // this is the maximum number of characters in a
    // path element / filename on windows and also on many filesystems commonly used
    // on linux
    #define TORRENT_MAX_PATH 255

    #ifdef _MSC_VER
    #pragma message ( "unknown platform, assuming the longest path is 255" )
    #else
    #warning "unknown platform, assuming the longest path is 255"
    #endif

    #endif

    #define TORRENT_UNUSED(x) (void)(x)

    #if (defined _MSC_VER && _MSC_VER < 1900) && !defined TORRENT_MINGW

relevance 0 | ../include/libtorrent/file.hpp:175 | move this into a separate header file, TU pair

## move this into a separate header file, TU pair

#### ../include/libtorrent/file.hpp:175

    	TORRENT_EXTRA_EXPORT std::string parent_path(std::string const& f);
    	TORRENT_EXTRA_EXPORT bool has_parent_path(std::string const& f);
    	TORRENT_EXTRA_EXPORT char const* filename_cstr(char const* f);

    	// internal used by create_torrent.hpp
    	TORRENT_EXTRA_EXPORT std::string filename(std::string const& f);
    	TORRENT_EXTRA_EXPORT std::string combine_path(std::string const& lhs
    		, std::string const& rhs);
    	TORRENT_EXTRA_EXPORT void append_path(std::string& branch
    		, std::string const& leaf);
    	TORRENT_EXTRA_EXPORT void append_path(std::string& branch
    		, char const* str, int len);
    	// internal used by create_torrent.hpp
    	TORRENT_EXTRA_EXPORT std::string complete(std::string const& f);
    	TORRENT_EXTRA_EXPORT bool is_complete(std::string const& f);
    	TORRENT_EXTRA_EXPORT std::string current_working_directory();
    #if TORRENT_USE_UNC_PATHS
    	TORRENT_EXTRA_EXPORT std::string canonicalize_path(std::string const& f);
    #endif

    	class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable
    	{
    	public:
    		directory(std::string const& path, error_code& ec);
    		~directory();
    		void next(error_code& ec);
    		std::string file() const;
    		boost::uint64_t inode() const;
    		bool done() const { return m_done; }
    	private:
    #ifdef TORRENT_WINDOWS
    		HANDLE m_handle;
    		int m_inode;
    #if TORRENT_USE_WSTRING
    		WIN32_FIND_DATAW m_fd;
    #else
    		WIN32_FIND_DATAA m_fd;
    #endif
    #else
    		DIR* m_handle;
    		// the dirent struct contains a zero-sized
    		// array at the end, it will end up referring
    		// to the m_name field
    		struct dirent m_dirent;
    		char m_name[TORRENT_MAX_PATH + 1]; // +1 to make room for null
    #endif
    		bool m_done;
    	};

    	struct file;

relevance 0 | ../include/libtorrent/heterogeneous_queue.hpp:184 | if this throws, should we do anything?

## if this throws, should we do anything?

#### ../include/libtorrent/heterogeneous_queue.hpp:184

    			- 1) / sizeof(uintptr_t);

    		void grow_capacity(int const size)
    		{
    			int const amount_to_grow = (std::max)(size + header_size
    				, (std::max)(m_capacity * 3 / 2, 128));

    			uintptr_t* new_storage = new uintptr_t[m_capacity + amount_to_grow];

    			uintptr_t* src = m_storage;
    			uintptr_t* dst = new_storage;
    			uintptr_t const* const end = m_storage + m_size;
    			while (src < end)
    			{
    				header_t* src_hdr = reinterpret_cast<header_t*>(src);
    				header_t* dst_hdr = reinterpret_cast<header_t*>(dst);
    				*dst_hdr = *src_hdr;
    				src += header_size;
    				dst += header_size;
    				TORRENT_ASSERT(src + src_hdr->len <= end);
    				src_hdr->move(dst, src);
    				src += src_hdr->len;
    				dst += src_hdr->len;
    			}

    			delete[] m_storage;
    			m_storage = new_storage;
    			m_capacity += amount_to_grow;
    		}

    		template <class U>
    		static void move(uintptr_t* dst, uintptr_t* src)
    		{
    			U* rhs = reinterpret_cast<U*>(src);
    #if __cplusplus >= 201103L
    			new (dst) U(std::move(*rhs));
    #else
    			new (dst) U(*rhs);
    #endif
    			rhs->~U();
    		}

    		uintptr_t* m_storage;
    		// number of uintptr_t's allocated under m_storage
    		int m_capacity;
    		// the number of uintptr_t's used under m_storage
    		int m_size;
    		// the number of objects allocated under m_storage
    		int m_num_items;
    	};
    }

relevance 0 | ../include/libtorrent/identify_client.hpp:47 | hide this declaration when deprecated functions are disabled, and remove its internal use

## hide this declaration when deprecated functions are disabled, and remove its internal use

#### ../include/libtorrent/identify_client.hpp:47

    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    */

    #ifndef TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED
    #define TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED

    #include "libtorrent/config.hpp"

    #ifndef TORRENT_NO_DEPRECATE
    #include "libtorrent/aux_/disable_warnings_push.hpp"
    #include <boost/optional.hpp>
    #include "libtorrent/aux_/disable_warnings_pop.hpp"
    #endif

    #include "libtorrent/peer_id.hpp"
    #include "libtorrent/fingerprint.hpp"

    namespace libtorrent
    {
    	// these functions don't really need to be public. This mechanism of
    	// advertising client software and version is also out-dated.

    	// This function can can be used to extract a string describing a client
    	// version from its peer-id. It will recognize most clients that have this
    	// kind of identification in the peer-id.
    	TORRENT_DEPRECATED_EXPORT TORRENT_DEPRECATED
    	std::string identify_client(const peer_id& p);

    #ifndef TORRENT_NO_DEPRECATE

    #ifdef __GNUC__
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    #endif
    #ifdef __clang__
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
    #endif
    	// Returns an optional fingerprint if any can be identified from the peer
    	// id. This can be used to automate the identification of clients. It will
    	// not be able to identify peers with non- standard encodings. Only Azureus
    	// style, Shadow's style and Mainline style.
    	TORRENT_DEPRECATED_EXPORT TORRENT_DEPRECATED
    	boost::optional<fingerprint>
    		client_fingerprint(peer_id const& p);

    #ifdef __GNUC__
    #pragma GCC diagnostic pop

relevance 0 | ../include/libtorrent/peer_connection.hpp:209 | make this a raw pointer (to save size in the first cache line) and make the constructor take a raw pointer. torrent objects should always outlive their peers

## make this a raw pointer (to save size in the first cache line) and make the constructor take a raw pointer. torrent objects should always outlive their peers

#### ../include/libtorrent/peer_connection.hpp:209

    			, m_connecting(!t.expired())
    			, m_endgame_mode(false)
    			, m_snubbed(false)
    			, m_interesting(false)
    			, m_choked(true)
    			, m_corked(false)
    			, m_ignore_stats(false)
    		{}

    	protected:

    		// the pieces the other end have
    		bitfield m_have_piece;

    		// this is the torrent this connection is
    		// associated with. If the connection is an
    		// incoming connection, this is set to zero
    		// until the info_hash is received. Then it's
    		// set to the torrent it belongs to.

    		boost::weak_ptr<torrent> m_torrent;

    	public:

    		// a back reference to the session
    		// the peer belongs to.
    		aux::session_interface& m_ses;

    		// settings that apply to this peer
    		aux::session_settings const& m_settings;

    	protected:

    		// this is true if this connection has been added
    		// to the list of connections that will be closed.
    		bool m_disconnecting:1;

    		// this is true until this socket has become
    		// writable for the first time (i.e. the
    		// connection completed). While connecting
    		// the timeout will not be triggered. This is
    		// because windows XP SP2 may delay connection
    		// attempts, which means that the connection
    		// may not even have been attempted when the
    		// time out is reached.
    		bool m_connecting:1;

    		// this is set to true if the last time we tried to
    		// pick a piece to download, we could only find
    		// blocks that were already requested from other
    		// peers. In this case, we should not try to pick

relevance 0 | ../include/libtorrent/peer_connection.hpp:1046 | factor this out into its own class with a virtual interface torrent and session should implement this interface

## factor this out into its own class with a virtual interface torrent and session should implement this interface

#### ../include/libtorrent/peer_connection.hpp:1046

    		// the local endpoint for this peer, i.e. our address
    		// and our port. If this is set for outgoing connections
    		// before the connection completes, it means we want to
    		// force the connection to be bound to the specified interface.
    		// if it ends up being bound to a different local IP, the connection
    		// is closed.
    		tcp::endpoint m_local;

    		// remote peer's id
    		peer_id m_peer_id;

    		// the bandwidth channels, upload and download
    		// keeps track of the current quotas
    		bandwidth_channel m_bandwidth_channel[num_channels];

    	protected:
    		// statistics about upload and download speeds
    		// and total amount of uploads and downloads for
    		// this peer
    		stat m_statistics;

    		// the number of outstanding bytes expected
    		// to be received by extensions
    		int m_extension_outstanding_bytes;

    		// the number of time critical requests
    		// queued up in the m_request_queue that
    		// soon will be committed to the download
    		// queue. This is included in download_queue_time()
    		// so that it can be used while adding more
    		// requests and take the previous requests
    		// into account without submitting it all
    		// immediately
    		int m_queued_time_critical;

    		// the number of bytes we are currently reading
    		// from disk, that will be added to the send
    		// buffer as soon as they complete
    		int m_reading_bytes;

    		// options used for the piece picker. These flags will
    		// be augmented with flags controlled by other settings
    		// like sequential download etc. These are here to
    		// let plugins control flags that should always be set
    		int m_picker_options;

    		// the number of invalid piece-requests
    		// we have got from this peer. If the request
    		// queue gets empty, and there have been
    		// invalid requests, we can assume the

relevance 0 | ../include/libtorrent/peer_connection_interface.hpp:47 | make this interface smaller!

## make this interface smaller!

#### ../include/libtorrent/peer_connection_interface.hpp:47

    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    */

    #ifndef TORRENT_PEER_CONNECTION_INTERFACE_HPP
    #define TORRENT_PEER_CONNECTION_INTERFACE_HPP

    #include "libtorrent/socket.hpp"
    #include "libtorrent/error_code.hpp"
    #include "libtorrent/alert_types.hpp"
    #include "libtorrent/operations.hpp" // for operation_t enum

    namespace libtorrent
    {
    	struct torrent_peer;
    	class stat;
    	struct peer_info;

    	struct TORRENT_EXTRA_EXPORT peer_connection_interface
    	{
    		virtual tcp::endpoint const& remote() const = 0;
    		virtual tcp::endpoint local_endpoint() const = 0;
    		virtual void disconnect(error_code const& ec
    			, operation_t op, int error = 0) = 0;
    		virtual peer_id const& pid() const = 0;
    		virtual void set_holepunch_mode() = 0;
    		virtual torrent_peer* peer_info_struct() const = 0;
    		virtual void set_peer_info(torrent_peer* pi) = 0;
    		virtual bool is_outgoing() const = 0;
    		virtual void add_stat(boost::int64_t downloaded, boost::int64_t uploaded) = 0;
    		virtual bool fast_reconnect() const = 0;
    		virtual bool is_choked() const = 0;
    		virtual bool failed() const = 0;
    		virtual stat const& statistics() const = 0;
    		virtual void get_peer_info(peer_info& p) const = 0;
    #ifndef TORRENT_DISABLE_LOGGING
    		virtual void peer_log(peer_log_alert::direction_t direction
    			, char const* event, char const* fmt = "", ...) const TORRENT_FORMAT(4,5) = 0;
    #endif
    	protected:
    		~peer_connection_interface() {}
    	};
    }

    #endif

relevance 0 | ../include/libtorrent/performance_counters.hpp:139 | should keepalives be in here too? how about dont-have, share-mode, upload-only

## should keepalives be in here too? how about dont-have, share-mode, upload-only

#### ../include/libtorrent/performance_counters.hpp:139

    			// a connect candidate
    			connection_attempt_loops,
    			// successful incoming connections (not rejected for any reason)
    			incoming_connections,

    			// counts events where the network
    			// thread wakes up
    			on_read_counter,
    			on_write_counter,
    			on_tick_counter,
    			on_lsd_counter,
    			on_lsd_peer_counter,
    			on_udp_counter,
    			on_accept_counter,
    			on_disk_queue_counter,
    			on_disk_counter,

    			torrent_evicted_counter,

    			// bittorrent message counters
    			num_incoming_choke,
    			num_incoming_unchoke,
    			num_incoming_interested,
    			num_incoming_not_interested,
    			num_incoming_have,
    			num_incoming_bitfield,
    			num_incoming_request,
    			num_incoming_piece,
    			num_incoming_cancel,
    			num_incoming_dht_port,
    			num_incoming_suggest,
    			num_incoming_have_all,
    			num_incoming_have_none,
    			num_incoming_reject,
    			num_incoming_allowed_fast,
    			num_incoming_ext_handshake,
    			num_incoming_pex,
    			num_incoming_metadata,
    			num_incoming_extended,

    			num_outgoing_choke,
    			num_outgoing_unchoke,
    			num_outgoing_interested,
    			num_outgoing_not_interested,
    			num_outgoing_have,
    			num_outgoing_bitfield,
    			num_outgoing_request,
    			num_outgoing_piece,
    			num_outgoing_cancel,
    			num_outgoing_dht_port,
    			num_outgoing_suggest,

relevance 0 | ../include/libtorrent/performance_counters.hpp:474 | some space could be saved here by making gauges 32 bits

## some space could be saved here by making gauges 32 bits

#### ../include/libtorrent/performance_counters.hpp:474

relevance 0 | ../include/libtorrent/performance_counters.hpp:475 | restore these to regular integers. Instead have one copy of the counters per thread and collect them at convenient synchronization points

## restore these to regular integers. Instead have one copy of the counters per thread and collect them at convenient synchronization points

#### ../include/libtorrent/performance_counters.hpp:475

    			num_utp_deleted,

    			num_counters,
    			num_gauges_counters = num_counters - num_stats_counters
    		};

    		counters();

    		counters(counters const&);
    		counters& operator=(counters const&);

    		// returns the new value
    		boost::int64_t inc_stats_counter(int c, boost::int64_t value = 1);
    		boost::int64_t operator[](int i) const;

    		void set_value(int c, boost::int64_t value);
    		void blend_stats_counter(int c, boost::int64_t value, int ratio);

    	private:

    #if BOOST_ATOMIC_LLONG_LOCK_FREE == 2
    		boost::atomic<boost::int64_t> m_stats_counter[num_counters];
    #else
    		// if the atomic type is't lock-free, use a single lock instead, for
    		// the whole array
    		mutable mutex m_mutex;
    		boost::int64_t m_stats_counter[num_counters];
    #endif
    	};
    }

    #endif

relevance 0 | ../include/libtorrent/piece_picker.hpp:756 | should this be allocated lazily?

## should this be allocated lazily?

#### ../include/libtorrent/piece_picker.hpp:756

    		std::vector<downloading_piece>::const_iterator find_dl_piece(int queue, int index) const;
    		std::vector<downloading_piece>::iterator find_dl_piece(int queue, int index);

    		// returns an iterator to the downloading piece, whichever
    		// download list it may live in now
    		std::vector<downloading_piece>::iterator update_piece_state(
    			std::vector<downloading_piece>::iterator dp);

    	private:

    		// the following vectors are mutable because they sometimes may
    		// be updated lazily, triggered by const functions

    		// this maps indices to number of peers that has this piece and
    		// index into the m_piece_info vectors.
    		// piece_pos::we_have_index means that we have the piece, so it
    		// doesn't exist in the piece_info buckets
    		// pieces with the filtered flag set doesn't have entries in
    		// the m_piece_info buckets either
    		mutable std::vector<piece_pos> m_piece_map;

    		// the number of seeds. These are not added to
    		// the availability counters of the pieces
    		int m_seeds;

    		// the number of pieces that have passed the hash check
    		int m_num_passed;

    		// this vector contains all piece indices that are pickable
    		// sorted by priority. Pieces are in random random order
    		// among pieces with the same priority
    		mutable std::vector<int> m_pieces;

    		// these are indices to the priority boundries inside
    		// the m_pieces vector. priority 0 always start at
    		// 0, priority 1 starts at m_priority_boundries[0] etc.
    		mutable std::vector<int> m_priority_boundries;

    		// each piece that's currently being downloaded has an entry in this list
    		// with block allocations. i.e. it says which parts of the piece that is
    		// being downloaded. This list is ordered by piece index to make lookups
    		// efficient there are as many buckets as there are piece states. See
    		// piece_pos::state_t. The only download state that does not have a
    		// corresponding downloading_piece vector is piece_open and
    		// piece_downloading_reverse (the latter uses the same as
    		// piece_downloading).
    		std::vector<downloading_piece> m_downloads[piece_pos::num_download_categories];

    		// this holds the information of the blocks in partially downloaded
    		// pieces. the downloading_piece::info index point into this vector for

relevance 0 | ../include/libtorrent/proxy_base.hpp:174 | it would be nice to remember the bind port and bind once we know where the proxy is m_sock.bind(endpoint, ec);

## it would be nice to remember the bind port and bind once we know where the proxy is m_sock.bind(endpoint, ec);

#### ../include/libtorrent/proxy_base.hpp:174

    	void bind(endpoint_type const& /* endpoint */)
    	{
    //		m_sock.bind(endpoint);
    	}
    #endif

    	error_code cancel(error_code& ec)
    	{
    		return m_sock.cancel(ec);
    	}

    	void bind(endpoint_type const& /* endpoint */, error_code& /* ec */)
    	{
    		// the reason why we ignore binds here is because we don't
    		// (necessarily) yet know what address family the proxy
    		// will resolve to, and binding to the wrong one would
    		// break our connection attempt later. The caller here
    		// doesn't necessarily know that we're proxying, so this
    		// bind address is based on the final endpoint, not the
    		// proxy.
    	}

    #ifndef BOOST_NO_EXCEPTIONS
    	void open(protocol_type const&)
    	{
    //		m_sock.open(p);
    	}
    #endif

    	void open(protocol_type const&, error_code&)
    	{
    		// we need to ignore this for the same reason as stated
    		// for ignoring bind()
    //		m_sock.open(p, ec);
    	}

    #ifndef BOOST_NO_EXCEPTIONS
    	void close()
    	{
    		m_remote_endpoint = endpoint_type();
    		m_sock.close();
    		m_resolver.cancel();
    	}
    #endif

    	void close(error_code& ec)
    	{
    		m_remote_endpoint = endpoint_type();
    		m_sock.close(ec);
    		m_resolver.cancel();
    	}

relevance 0 | ../include/libtorrent/receive_buffer.hpp:272 | Detect when the start of the next crpyto packet is aligned with the start of piece data and the crpyto packet is at least as large as the piece data. With a little extra work we could receive directly into a disk buffer in that case.

## Detect when the start of the next crpyto packet is aligned with the start of piece data and the crpyto packet is at least as large as the piece data. With a little extra work we could receive directly into a disk buffer in that case.

#### ../include/libtorrent/receive_buffer.hpp:272

    	void cut(int size, int packet_size, int offset = 0);

    	void crypto_cut(int size, int packet_size)
    	{
    		TORRENT_ASSERT(m_recv_pos != INT_MAX);
    		m_connection_buffer.cut(size, m_recv_pos + packet_size, m_recv_pos);
    	}

    	void reset(int packet_size);
    	void crypto_reset(int packet_size);

    	void set_soft_packet_size(int size);

    	int advance_pos(int bytes);

    	buffer::const_interval get() const;

    	bool can_recv_contiguous(int /*size*/) const
    	{
    		return m_recv_pos == INT_MAX;
    	}

    	void mutable_buffers(std::vector<boost::asio::mutable_buffer>& vec
    		, std::size_t bytes_transfered);

    private:
    	// explicitly disallow assignment, to silence msvc warning
    	crypto_receive_buffer& operator=(crypto_receive_buffer const&);

    	int m_recv_pos;
    	int m_packet_size;
    	int m_soft_packet_size;
    	receive_buffer& m_connection_buffer;
    };
    #endif // TORRENT_DISABLE_ENCRYPTION

    } // namespace libtorrent

    #endif // #ifndef TORRENT_RECEIVE_BUFFER_HPP_INCLUDED

relevance 0 | ../include/libtorrent/session_handle.hpp:670 | add get_peer_class_type_filter() as well

## add get_peer_class_type_filter() as well

#### ../include/libtorrent/session_handle.hpp:670

    		//
    		// The ``peer_class`` argument cannot be greater than 31. The bitmasks
    		// representing peer classes in the ``peer_class_filter`` are 32 bits.
    		//
    		// For more information, see peer-classes_.
    		void set_peer_class_filter(ip_filter const& f);

    		// Sets and gets the *peer class type filter*. This is controls automatic
    		// peer class assignments to peers based on what kind of socket it is.
    		//
    		// It does not only support assigning peer classes, it also supports
    		// removing peer classes based on socket type.
    		//
    		// The order of these rules being applied are:
    		//
    		// 1. peer-class IP filter
    		// 2. peer-class type filter, removing classes
    		// 3. peer-class type filter, adding classes
    		//
    		// For more information, see peer-classes_.
    		void set_peer_class_type_filter(peer_class_type_filter const& f);

    		// Creates a new peer class (see peer-classes_) with the given name. The
    		// returned integer is the new peer class identifier. Peer classes may
    		// have the same name, so each invocation of this function creates a new
    		// class and returns a unique identifier.
    		//
    		// Identifiers are assigned from low numbers to higher. So if you plan on
    		// using certain peer classes in a call to `set_peer_class_filter()`_,
    		// make sure to create those early on, to get low identifiers.
    		//
    		// For more information on peer classes, see peer-classes_.
    		int create_peer_class(char const* name);

    		// This call dereferences the reference count of the specified peer
    		// class. When creating a peer class it's automatically referenced by 1.
    		// If you want to recycle a peer class, you may call this function. You
    		// may only call this function **once** per peer class you create.
    		// Calling it more than once for the same class will lead to memory
    		// corruption.
    		//
    		// Since peer classes are reference counted, this function will not
    		// remove the peer class if it's still assigned to torrents or peers. It
    		// will however remove it once the last peer and torrent drops their
    		// references to it.
    		//
    		// There is no need to call this function for custom peer classes. All
    		// peer classes will be properly destructed when the session object
    		// destructs.
    		//
    		// For more information on peer classes, see peer-classes_.

relevance 0 | ../include/libtorrent/settings_pack.hpp:1141 | deprecate this ``max_rejects`` is the number of piece requests we will reject in a row while a peer is choked before the peer is considered abusive and is disconnected.

## deprecate this ``max_rejects`` is the number of piece requests we will reject in a row while a peer is choked before the peer is considered abusive and is disconnected.

#### ../include/libtorrent/settings_pack.hpp:1141

    			// this is the minimum allowed announce interval for a tracker. This
    			// is specified in seconds and is used as a sanity check on what is
    			// returned from a tracker. It mitigates hammering misconfigured
    			// trackers.
    			min_announce_interval,

    			// this is the number of seconds a torrent is considered active after
    			// it was started, regardless of upload and download speed. This is so
    			// that newly started torrents are not considered inactive until they
    			// have a fair chance to start downloading.
    			auto_manage_startup,

    			// ``seeding_piece_quota`` is the number of pieces to send to a peer,
    			// when seeding, before rotating in another peer to the unchoke set.
    			// It defaults to 3 pieces, which means that when seeding, any peer
    			// we've sent more than this number of pieces to will be unchoked in
    			// favour of a choked peer.
    			seeding_piece_quota,

    			max_rejects,

    			// ``recv_socket_buffer_size`` and ``send_socket_buffer_size``
    			// specifies the buffer sizes set on peer sockets. 0 (which is the
    			// default) means the OS default (i.e. don't change the buffer sizes).
    			// The socket buffer sizes are changed using setsockopt() with
    			// SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER.
    			recv_socket_buffer_size,
    			send_socket_buffer_size,

    #ifndef TORRENT_NO_DEPRECATE
    			// ``file_checks_delay_per_block`` is the number of milliseconds to
    			// sleep in between disk read operations when checking torrents. This
    			// defaults to 0, but can be set to higher numbers to slow down the
    			// rate at which data is read from the disk while checking. This may
    			// be useful for background tasks that doesn't matter if they take a
    			// bit longer, as long as they leave disk I/O time for other
    			// processes.
    			file_checks_delay_per_block TORRENT_DEPRECATED_ENUM,
    #else
    			deprecated14,
    #endif

    			// ``read_cache_line_size`` is the number of blocks to read into the
    			// read cache when a read cache miss occurs. Setting this to 0 is
    			// essentially the same thing as disabling read cache. The number of
    			// blocks read into the read cache is always capped by the piece
    			// boundary.
    			//
    			// When a piece in the write cache has ``write_cache_line_size``
    			// contiguous blocks in it, they will be flushed. Setting this to 1

relevance 0 | ../include/libtorrent/torrent.hpp:207 | make this a raw pointer. perhaps keep the shared_ptr around further down the object to maintain an owner

## make this a raw pointer. perhaps keep the shared_ptr around further down the object to maintain an owner

#### ../include/libtorrent/torrent.hpp:207

    		// connection to pick up
    		peer_request restart_request;
    		std::vector<char> restart_piece;
    	};

    	struct TORRENT_EXTRA_EXPORT torrent_hot_members
    	{
    		torrent_hot_members(aux::session_interface& ses
    			, add_torrent_params const& p, int block_size);

    	protected:
    		// the piece picker. This is allocated lazily. When we don't
    		// have anything in the torrent (for instance, if it hasn't
    		// been started yet) or if we have everything, there is no
    		// picker. It's allocated on-demand the first time we need
    		// it in torrent::need_picker(). In order to tell the
    		// difference between having everything and nothing in
    		// the case there is no piece picker, see m_have_all.
    		boost::scoped_ptr<piece_picker> m_picker;

    		boost::shared_ptr<torrent_info> m_torrent_file;

    		// a back reference to the session
    		// this torrent belongs to.
    		aux::session_interface& m_ses;

    		// this vector is sorted at all times, by the pointer value.
    		// use sorted_insert() and sorted_find() on it. The GNU STL
    		// implementation on Darwin uses significantly less memory to
    		// represent a vector than a set, and this set is typically
    		// relatively small, and it's cheap to copy pointers.
    		std::vector<peer_connection*> m_connections;

    		// the scrape data from the tracker response, this
    		// is optional and may be 0xffffff
    		boost::uint32_t m_complete:24;

    		// set to true when this torrent may not download anything
    		bool m_upload_mode:1;

    		// this is set to false as long as the connections
    		// of this torrent hasn't been initialized. If we
    		// have metadata from the start, connections are
    		// initialized immediately, if we didn't have metadata,
    		// they are initialized right after files_checked().
    		// valid_resume_data() will return false as long as
    		// the connections aren't initialized, to avoid
    		// them from altering the piece-picker before it
    		// has been initialized with files_checked().
    		bool m_connections_initialized:1;

relevance 0 | ../include/libtorrent/torrent.hpp:1286 | this wastes 5 bits per file

## this wastes 5 bits per file

#### ../include/libtorrent/torrent.hpp:1286

    		typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
    		extension_list_t m_extensions;
    #endif

    		// used for tracker announces
    		deadline_timer m_tracker_timer;

    		// used to detect when we are active or inactive for long enough
    		// to trigger the auto-manage logic
    		deadline_timer m_inactivity_timer;

    		// this is the upload and download statistics for the whole torrent.
    		// it's updated from all its peers once every second.
    		libtorrent::stat m_stat;

    		// -----------------------------

    		// this vector is allocated lazily. If no file priorities are
    		// ever changed, this remains empty. Any unallocated slot
    		// implicitly means the file has priority 1.
    		std::vector<boost::uint8_t> m_file_priority;

    		// this object is used to track download progress of individual files
    		aux::file_progress m_file_progress;

    		// these are the pieces we're currently
    		// suggesting to peers.
    		std::vector<suggest_piece_t> m_suggested_pieces;

    		std::vector<announce_entry> m_trackers;
    		// this is an index into m_trackers

    		// this list is sorted by time_critical_piece::deadline
    		std::vector<time_critical_piece> m_time_critical_pieces;

    		std::string m_trackerid;
    #ifndef TORRENT_NO_DEPRECATE
    		// deprecated in 1.1
    		std::string m_username;
    		std::string m_password;
    #endif

    		std::string m_save_path;

    		// if we don't have the metadata, this is a url to
    		// the torrent file
    		std::string m_url;

    		// if this was added from an RSS feed, this is the unique
    		// identifier in the feed.
    		std::string m_uuid;

relevance 0 | ../include/libtorrent/torrent.hpp:1344 | These two bitfields should probably be coalesced into one

## These two bitfields should probably be coalesced into one

#### ../include/libtorrent/torrent.hpp:1344

    		// the .torrent file from m_url
    //		std::vector<char> m_torrent_file_buf;

    		// this is a list of all pieces that we have announced
    		// as having, without actually having yet. If we receive
    		// a request for a piece in this list, we need to hold off
    		// on responding until we have completed the piece and
    		// verified its hash. If the hash fails, send reject to
    		// peers with outstanding requests, and dont_have to other
    		// peers. This vector is ordered, to make lookups fast.
    		std::vector<int> m_predictive_pieces;

    		// the performance counters of this session
    		counters& m_stats_counters;

    		// each bit represents a piece. a set bit means
    		// the piece has had its hash verified. This
    		// is only used in seed mode (when m_seed_mode
    		// is true)

    		bitfield m_verified;
    		// this means there is an outstanding, async, operation
    		// to verify each piece that has a 1
    		bitfield m_verifying;

    		// set if there's an error on this torrent
    		error_code m_error;

    		// used if there is any resume data
    		boost::scoped_ptr<resume_data_t> m_resume_data;

    		// if the torrent is started without metadata, it may
    		// still be given a name until the metadata is received
    		// once the metadata is received this field will no
    		// longer be used and will be reset
    		boost::scoped_ptr<std::string> m_name;

    		storage_constructor_type m_storage_constructor;

    		// the posix time this torrent was added and when
    		// it was completed. If the torrent isn't yet
    		// completed, m_completed_time is 0
    		time_t m_added_time;
    		time_t m_completed_time;

    		// this was the last time _we_ saw a seed in this swarm
    		time_t m_last_seen_complete;

    		// this is the time last any of our peers saw a seed
    		// in this swarm
    		time_t m_swarm_last_seen_complete;

relevance 0 | ../include/libtorrent/torrent_info.hpp:117 | there may be some opportunities to optimize the size if torrent_info. specifically to turn some std::string and std::vector into pointers

## there may be some opportunities to optimize the size if torrent_info. specifically to turn some std::string and std::vector into pointers

#### ../include/libtorrent/torrent_info.hpp:117

    		// The URL of the web seed
    		std::string url;

    		// Optional authentication. If this is set, it's passed
    		// in as HTTP basic auth to the web seed. The format is:
    		// username:password.
    		std::string auth;

    		// Any extra HTTP headers that need to be passed to the web seed
    		headers_t extra_headers;

    		// The type of web seed (see type_t)
    		boost::uint8_t type;
    	};

    #ifndef BOOST_NO_EXCEPTIONS
    	// for backwards compatibility with 0.14
    	typedef libtorrent_exception invalid_torrent_file;
    #endif

    	class TORRENT_EXPORT torrent_info
    	{
    	public:

    		// The constructor that takes an info-hash  will initialize the info-hash
    		// to the given value, but leave all other fields empty. This is used
    		// internally when downloading torrents without the metadata. The
    		// metadata will be created by libtorrent as soon as it has been
    		// downloaded from the swarm.
    		//
    		// The constructor that takes a bdecode_node will create a torrent_info
    		// object from the information found in the given torrent_file. The
    		// bdecode_node represents a tree node in an bencoded file. To load an
    		// ordinary .torrent file into a bdecode_node, use bdecode().
    		//
    		// The version that takes a buffer pointer and a size will decode it as a
    		// .torrent file and initialize the torrent_info object for you.
    		//
    		// The version that takes a filename will simply load the torrent file
    		// and decode it inside the constructor, for convenience. This might not
    		// be the most suitable for applications that want to be able to report
    		// detailed errors on what might go wrong.
    		//
    		// There is an upper limit on the size of the torrent file that will be
    		// loaded by the overload taking a filename. If it's important that even
    		// very large torrent files are loaded, use one of the other overloads.
    		//
    		// The overloads that takes an ``error_code const&`` never throws if an
    		// error occur, they will simply set the error code to describe what went
    		// wrong and not fully initialize the torrent_info object. The overloads
    		// that do not take the extra error_code parameter will always throw if

relevance 0 | ../include/libtorrent/tracker_manager.hpp:413 | this should be unique_ptr in the future

## this should be unique_ptr in the future

#### ../include/libtorrent/tracker_manager.hpp:413

    		// this is only used for SOCKS packets, since
    		// they may be addressed to hostname
    		virtual bool incoming_packet(error_code const& e, char const* hostname
    			, char const* buf, int size) TORRENT_OVERRIDE;

    		void update_transaction_id(
    			boost::shared_ptr<udp_tracker_connection> c
    			, boost::uint64_t tid);

    		aux::session_settings const& settings() const { return m_settings; }
    		udp_socket& get_udp_socket() { return m_udp_socket; }
    		resolver_interface& host_resolver() { return m_host_resolver; }

    	private:

    		typedef mutex mutex_t;
    		mutable mutex_t m_mutex;

    		// maps transactionid to the udp_tracker_connection
    		typedef boost::unordered_map<boost::uint32_t
    			, boost::shared_ptr<udp_tracker_connection> > udp_conns_t;
    		udp_conns_t m_udp_conns;

    		typedef std::vector<boost::shared_ptr<http_tracker_connection> > http_conns_t;
    		http_conns_t m_http_conns;

    		class udp_socket& m_udp_socket;
    		resolver_interface& m_host_resolver;
    		aux::session_settings const& m_settings;
    		counters& m_stats_counters;
    #if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
    		aux::session_logger& m_ses;
    #endif

    		bool m_abort;
    	};
    }

    #endif // TORRENT_TRACKER_MANAGER_HPP_INCLUDED

relevance 0 | ../include/libtorrent/upnp.hpp:158 | support using the windows API for UPnP operations as well

## support using the windows API for UPnP operations as well

#### ../include/libtorrent/upnp.hpp:158

    	bool exit;
    	int error_code;
    };

    struct ip_address_parse_state: error_code_parse_state
    {
    	ip_address_parse_state(): in_ip_address(false) {}
    	bool in_ip_address;
    	std::string ip_address;
    };

    TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string
    	, int str_len, parse_state& state);

    TORRENT_EXTRA_EXPORT void find_error_code(int type, char const* string
    	, int str_len, error_code_parse_state& state);

    TORRENT_EXTRA_EXPORT void find_ip_address(int type, char const* string
    	, int str_len, ip_address_parse_state& state);

    class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this<upnp>
    {
    public:
    	upnp(io_service& ios
    		, address const& listen_interface, std::string const& user_agent
    		, portmap_callback_t const& cb, log_callback_t const& lcb
    		, bool ignore_nonrouters);
    	~upnp();

    	void set_user_agent(std::string const& v) { m_user_agent = v; }

    	void start();

    	enum protocol_type { none = 0, udp = 1, tcp = 2 };

    	// Attempts to add a port mapping for the specified protocol. Valid protocols are
    	// ``upnp::tcp`` and ``upnp::udp`` for the UPnP class and ``natpmp::tcp`` and
    	// ``natpmp::udp`` for the NAT-PMP class.
    	//
    	// ``external_port`` is the port on the external address that will be mapped. This
    	// is a hint, you are not guaranteed that this port will be available, and it may
    	// end up being something else. In the portmap_alert_ notification, the actual
    	// external port is reported.
    	//
    	// ``local_port`` is the port in the local machine that the mapping should forward
    	// to.
    	//
    	// The return value is an index that identifies this port mapping. This is used
    	// to refer to mappings that fails or succeeds in the portmap_error_alert_ and
    	// portmap_alert_ respectively. If The mapping fails immediately, the return value
    	// is -1, which means failure. There will not be any error alert notification for

relevance 0 | ../include/libtorrent/utp_stream.hpp:424 | implement blocking write. Low priority since it's not used (yet)

## implement blocking write. Low priority since it's not used (yet)

#### ../include/libtorrent/utp_stream.hpp:424

    		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
    			, end(buffers.end()); i != end; ++i)
    		{
    			using boost::asio::buffer_cast;
    			using boost::asio::buffer_size;
    			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
    #if TORRENT_USE_ASSERTS
    			buf_size += buffer_size(*i);
    #endif
    		}
    		std::size_t ret = read_some(true);
    		TORRENT_ASSERT(ret <= buf_size);
    		TORRENT_ASSERT(ret > 0);
    		return ret;
    	}

    	template <class Const_Buffers>
    	std::size_t write_some(Const_Buffers const& /* buffers */, error_code& /* ec */)
    	{
    		TORRENT_ASSERT(false && "not implemented!");
    		return 0;
    	}

    #ifndef BOOST_NO_EXCEPTIONS
    	template <class Mutable_Buffers>
    	std::size_t read_some(Mutable_Buffers const& buffers)
    	{
    		error_code ec;
    		std::size_t ret = read_some(buffers, ec);
    		if (ec)
    			boost::throw_exception(boost::system::system_error(ec));
    		return ret;
    	}

    	template <class Const_Buffers>
    	std::size_t write_some(Const_Buffers const& buffers)
    	{
    		error_code ec;
    		std::size_t ret = write_some(buffers, ec);
    		if (ec)
    			boost::throw_exception(boost::system::system_error(ec));
    		return ret;
    	}
    #endif

    	template <class Const_Buffers, class Handler>
    	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
    	{
    		if (m_impl == 0)
    		{
    			m_io_service.post(boost::bind<void>(handler

relevance 0 | ../include/libtorrent/kademlia/item.hpp:61 | since this is a public function, it should probably be moved out of this header and into one with other public functions.

## since this is a public function, it should probably be moved out of this header and into one with other public functions.

#### ../include/libtorrent/kademlia/item.hpp:61

    #include <boost/array.hpp>

    namespace libtorrent { namespace dht
    {

    // calculate the target hash for an immutable item.
    sha1_hash TORRENT_EXTRA_EXPORT item_target_id(
    	std::pair<char const*, int> v);

    // calculate the target hash for a mutable item.
    sha1_hash TORRENT_EXTRA_EXPORT item_target_id(std::pair<char const*, int> salt
    	, char const* pk);

    bool TORRENT_EXTRA_EXPORT verify_mutable_item(
    	std::pair<char const*, int> v
    	, std::pair<char const*, int> salt
    	, boost::uint64_t seq
    	, char const* pk
    	, char const* sig);

    // given a byte range ``v`` and an optional byte range ``salt``, a
    // sequence number, public key ``pk`` (must be 32 bytes) and a secret key
    // ``sk`` (must be 64 bytes), this function produces a signature which
    // is written into a 64 byte buffer pointed to by ``sig``. The caller
    // is responsible for allocating the destination buffer that's passed in
    // as the ``sig`` argument. Typically it would be allocated on the stack.
    void TORRENT_EXPORT sign_mutable_item(
    	std::pair<char const*, int> v
    	, std::pair<char const*, int> salt
    	, boost::uint64_t seq
    	, char const* pk
    	, char const* sk
    	, char* sig);

    enum
    {
    	item_pk_len = 32,
    	item_sk_len = 64,
    	item_sig_len = 64
    };

    class TORRENT_EXTRA_EXPORT item
    {
    public:
    	item() : m_seq(0), m_mutable(false)  {}
    	item(char const* pk, std::string const& salt);
    	item(entry const& v) { assign(v); }
    	item(entry const& v
    		, std::pair<char const*, int> salt
    		, boost::uint64_t seq, char const* pk, char const* sk);

relevance 0 | ../include/libtorrent/aux_/session_impl.hpp:867 | should this be renamed m_outgoing_interfaces?

## should this be renamed m_outgoing_interfaces?

#### ../include/libtorrent/aux_/session_impl.hpp:867

    			// client with the tracker only. It is randomized
    			// at startup
    			int m_key;

    			// the addresses or device names of the interfaces we are supposed to
    			// listen on. if empty, it means that we should let the os decide
    			// which interface to listen on
    			std::vector<std::pair<std::string, int> > m_listen_interfaces;

    			// keep this around until everything uses the list of interfaces
    			// instead.
    			tcp::endpoint m_listen_interface;

    			// the network interfaces outgoing connections are opened through. If
    			// there is more then one, they are used in a round-robin fashion
    			// each element is a device name or IP address (in string form) and
    			// a port number. The port determines which port to bind the listen
    			// socket to, and the device or IP determines which network adapter
    			// to be used. If no adapter with the specified name exists, the listen
    			// socket fails.
    			std::vector<std::string> m_net_interfaces;

    			// if we're listening on an IPv6 interface
    			// this is one of the non local IPv6 interfaces
    			// on this machine
    			tcp::endpoint m_ipv6_interface;
    			tcp::endpoint m_ipv4_interface;

    			// since we might be listening on multiple interfaces
    			// we might need more than one listen socket
    			std::list<listen_socket_t> m_listen_sockets;

    #if TORRENT_USE_I2P
    			i2p_connection m_i2p_conn;
    			boost::shared_ptr<socket_type> m_i2p_listen_socket;
    #endif

    #ifdef TORRENT_USE_OPENSSL
    			ssl::context* ssl_ctx() TORRENT_OVERRIDE { return &m_ssl_ctx; }
    			void on_incoming_utp_ssl(boost::shared_ptr<socket_type> const& s);
    			void ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s);
    #endif

    			// round-robin index into m_net_interfaces
    			mutable boost::uint8_t m_interface_index;

    			enum listen_on_flags_t
    			{
    				open_ssl_socket = 0x10
    			};

relevance 0 | ../include/libtorrent/aux_/session_impl.hpp:912 | replace this by a proper asio timer

## replace this by a proper asio timer

#### ../include/libtorrent/aux_/session_impl.hpp:912

    			mutable boost::uint8_t m_interface_index;

    			enum listen_on_flags_t
    			{
    				open_ssl_socket = 0x10
    			};

    			listen_socket_t setup_listener(std::string const& device
    				, boost::asio::ip::tcp const& protocol, int port, int flags
    				, error_code& ec);

    #ifndef TORRENT_DISABLE_DHT
    			entry m_dht_state;
    #endif

    			// this is initialized to the unchoke_interval
    			// session_setting and decreased every second.
    			// when it reaches zero, it is reset to the
    			// unchoke_interval and the unchoke set is
    			// recomputed.
    			int m_unchoke_time_scaler;

    			// this is used to decide when to recalculate which
    			// torrents to keep queued and which to activate

relevance 0 | ../include/libtorrent/aux_/session_impl.hpp:917 | replace this by a proper asio timer

## replace this by a proper asio timer

#### ../include/libtorrent/aux_/session_impl.hpp:917

    				open_ssl_socket = 0x10
    			};

    			listen_socket_t setup_listener(std::string const& device
    				, boost::asio::ip::tcp const& protocol, int port, int flags
    				, error_code& ec);

    #ifndef TORRENT_DISABLE_DHT
    			entry m_dht_state;
    #endif

    			// this is initialized to the unchoke_interval
    			// session_setting and decreased every second.
    			// when it reaches zero, it is reset to the
    			// unchoke_interval and the unchoke set is
    			// recomputed.
    			int m_unchoke_time_scaler;

    			// this is used to decide when to recalculate which
    			// torrents to keep queued and which to activate
    			int m_auto_manage_time_scaler;

    			// works like unchoke_time_scaler but it
    			// is only decreased when the unchoke set
    			// is recomputed, and when it reaches zero,
    			// the optimistic unchoke is moved to another peer.

relevance 0 | ../include/libtorrent/aux_/session_impl.hpp:924 | replace this by a proper asio timer

## replace this by a proper asio timer

#### ../include/libtorrent/aux_/session_impl.hpp:924

    #ifndef TORRENT_DISABLE_DHT
    			entry m_dht_state;
    #endif

    			// this is initialized to the unchoke_interval
    			// session_setting and decreased every second.
    			// when it reaches zero, it is reset to the
    			// unchoke_interval and the unchoke set is
    			// recomputed.
    			int m_unchoke_time_scaler;

    			// this is used to decide when to recalculate which
    			// torrents to keep queued and which to activate
    			int m_auto_manage_time_scaler;

    			// works like unchoke_time_scaler but it
    			// is only decreased when the unchoke set
    			// is recomputed, and when it reaches zero,
    			// the optimistic unchoke is moved to another peer.
    			int m_optimistic_unchoke_time_scaler;

    			// works like unchoke_time_scaler. Each time
    			// it reaches 0, and all the connections are
    			// used, the worst connection will be disconnected
    			// from the torrent with the most peers
    			int m_disconnect_time_scaler;

    			// when this scaler reaches zero, it will
    			// scrape one of the auto managed, paused,
    			// torrents.
    			int m_auto_scrape_time_scaler;

    #ifndef TORRENT_NO_DEPRECATE
    			// the index of the torrent that we'll
    			// refresh the next time
    			int m_next_explicit_cache_torrent;

    			// this is a counter of the number of seconds until
    			// the next time the read cache is rotated, if we're
    			// using an explicit read read cache.
    			int m_cache_rotation_timer;
    #endif

    			// the index of the torrent that we'll
    			// refresh the next time
    			int m_next_suggest_torrent;

    			// this is a counter of the number of seconds until
    			// the next time the suggest pieces are refreshed
    			int m_suggest_timer;

relevance 0 | ../include/libtorrent/aux_/session_interface.hpp:248 | it would be nice to not have this be part of session_interface

## it would be nice to not have this be part of session_interface

#### ../include/libtorrent/aux_/session_interface.hpp:248

    		// load the specified torrent. also evict one torrent, except
    		// for the one specified, if we are at the limit of loaded torrents
    		virtual bool load_torrent(torrent* t) = 0;

    		// bump the specified torrent to make it the most recently used one
    		// in the torrent LRU (i.e. the least likely to get unloaded)
    		virtual void bump_torrent(torrent* t, bool back = true) = 0;

    		// ask for which interface and port to bind outgoing peer connections on
    		virtual tcp::endpoint bind_outgoing_socket(socket_type& s, address const&
    			remote_address, error_code& ec) const = 0;
    		virtual bool verify_bound_address(address const& addr, bool utp
    			, error_code& ec) = 0;

    #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
    		virtual std::vector<boost::shared_ptr<torrent> > find_collection(
    			std::string const& collection) const = 0;
    #endif

    		virtual proxy_settings proxy() const = 0;

    #if TORRENT_USE_I2P
    		virtual proxy_settings i2p_proxy() const = 0;
    		virtual char const* i2p_session() const = 0;
    #endif

    		virtual void prioritize_connections(boost::weak_ptr<torrent> t) = 0;

    		virtual tcp::endpoint get_ipv6_interface() const = 0;
    		virtual tcp::endpoint get_ipv4_interface() const = 0;

    		virtual void trigger_auto_manage() = 0;

    		virtual void apply_settings_pack(boost::shared_ptr<settings_pack> pack) = 0;
    		virtual session_settings const& settings() const = 0;

    		virtual void queue_tracker_request(tracker_request& req
    			, boost::weak_ptr<request_callback> c) = 0;

    		// peer-classes
    		virtual void set_peer_classes(peer_class_set* s, address const& a, int st) = 0;
    		virtual peer_class_pool const& peer_classes() const = 0;
    		virtual peer_class_pool& peer_classes() = 0;
    		virtual bool ignore_unchoke_slots_set(peer_class_set const& set) const = 0;
    		virtual int copy_pertinent_channels(peer_class_set const& set
    			, int channel, bandwidth_channel** dst, int max) = 0;
    		virtual int use_quota_overhead(peer_class_set& set, int amount_down, int amount_up) = 0;

    		virtual bandwidth_manager* get_bandwidth_manager(int channel) = 0;

relevance 0 | ../include/libtorrent/aux_/session_settings.hpp:78 | make this a bitfield

## make this a bitfield

#### ../include/libtorrent/aux_/session_settings.hpp:78

    	if ((name & settings_pack::type_mask) != settings_pack:: type ## _type_base) return default_val; \
    	return m_ ## type ## s[name - settings_pack:: type ## _type_base]

    	struct TORRENT_EXTRA_EXPORT session_settings
    	{
    		friend void libtorrent::save_settings_to_dict(
    			aux::session_settings const& s, entry::dictionary_type& sett);

    		void set_str(int name, std::string const& value) { SET(string); }
    		std::string const& get_str(int name) const { GET(string, m_strings[0]); }
    		void set_int(int name, int value) { SET(int); }
    		int get_int(int name) const { GET(int, 0); }
    		void set_bool(int name, bool value) { SET(bool); }
    		bool get_bool(int name) const { GET(bool, false); }

    		session_settings();

    	private:
    		std::string m_strings[settings_pack::num_string_settings];
    		int m_ints[settings_pack::num_int_settings];
    		bool m_bools[settings_pack::num_bool_settings];
    	};

    #undef GET
    #undef SET

    } }

    #endif