relevance 3 | ../src/piece_picker.cpp:155 | we need a different type to return to the outside here |
we need a different type to return to the outside here../src/piece_picker.cpp:155
m_blocks_per_piece = blocks_per_piece;
m_blocks_in_last_piece = blocks_in_last_piece;
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece;
TORRENT_ASSERT(m_blocks_in_last_piece <= m_blocks_per_piece);
}
void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const
{
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#endif
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < int(m_piece_map.size()));
int state = m_piece_map[index].download_queue();
if (state != piece_pos::piece_open)
{
std::vector<downloading_piece>::const_iterator piece = find_dl_piece(state, index);
TORRENT_ASSERT(piece != m_downloads[state].end());
st = *piece;
return;
}
st.info_idx = 0;
st.index = index;
st.writing = 0;
st.requested = 0;
if (m_piece_map[index].have())
{
st.finished = blocks_in_piece(index);
return;
}
st.finished = 0;
}
piece_picker::piece_stats_t piece_picker::piece_stats(int index) const
{
TORRENT_ASSERT(index >= 0 && index < int(m_piece_map.size()));
piece_pos const& pp = m_piece_map[index];
piece_stats_t ret = {
pp.peer_count + m_seeds,
pp.priority(this),
pp.have(),
pp.downloading()
};
return ret;
}
piece_picker::dlpiece_iter piece_picker::add_download_piece(int piece)
| ||
relevance 3 | ../src/kademlia/get_item.cpp:220 | we don't support CAS errors here! we need a custom observer |
we don't support CAS errors here! we need a custom observer../src/kademlia/get_item.cpp:220 TORRENT_LOG(node) << "sending put [ v: \"" << m_data.value()
<< "\" seq: " << (m_data.is_mutable() ? m_data.seq() : -1)
<< " nodes: " << v.size() << " ]" ;
#endif
// create a dummy traversal_algorithm
boost::intrusive_ptr<traversal_algorithm> algo(
new traversal_algorithm(m_node, (node_id::min)()));
// store on the first k nodes
for (std::vector<std::pair<node_entry, std::string> >::const_iterator i = v.begin()
, end(v.end()); i != end; ++i)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(node) << " put-distance: " << (160 - distance_exp(m_target, i->first.id));
#endif
void* ptr = m_node.m_rpc.allocate_observer();
if (ptr == 0) return;
observer_ptr o(new (ptr) announce_observer(algo, i->first.ep(), i->first.id));
#if TORRENT_USE_ASSERTS
o->m_in_constructor = false;
#endif
entry e;
e["y"] = "q";
e["q"] = "put";
entry& a = e["a"];
a["v"] = m_data.value();
a["token"] = i->second;
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();
}
}
m_node.m_rpc.invoke(e, i->first.ep(), o);
}
}
void get_item_observer::reply(msg const& m)
{
char const* pk = NULL;
char const* sig = NULL;
boost::uint64_t seq = 0;
lazy_entry const* r = m.message.dict_find_dict("r");
| ||
relevance 2 | ../src/peer_connection.cpp:2989 | 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:2989
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);
#if defined TORRENT_LOGGING
peer_log("==> REJECT_PIECE [ piece: %d s: %x l: %x ] cancelled"
, r.piece , r.start , r.length);
#endif
write_reject_request(r);
}
else
{
#if defined TORRENT_LOGGING
peer_log("*** 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;
#if defined TORRENT_LOGGING
peer_log("<== DHT_PORT [ p: %d ]", listen_port);
#endif
#ifndef TORRENT_DISABLE_DHT
m_ses.add_dht_node(udp::endpoint(
m_remote.address(), listen_port));
#endif
}
// -----------------------------
// --------- HAVE ALL ----------
// -----------------------------
void peer_connection::incoming_have_all()
{
TORRENT_ASSERT(is_single_thread());
| ||
relevance 2 | ../src/peer_connection.cpp:4575 | 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:4575 if (is_i2p(*m_socket))
connect_timeout += 20;
#endif
if (d > seconds(connect_timeout)
&& can_disconnect(error_code(errors::timed_out, get_libtorrent_category())))
{
#if defined TORRENT_LOGGING
peer_log("*** 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(error_code(errors::timed_out_inactivity, get_libtorrent_category())))
{
#if defined TORRENT_LOGGING
peer_log("*** 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
if (may_timeout
&& !m_connecting
&& in_handshake()
&& d > seconds(m_settings.get_int(settings_pack::handshake_timeout)))
{
#if defined TORRENT_LOGGING
peer_log("*** 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 within 60 seconds.
// but only if we're a seed
d = now - (std::max)(m_last_unchoke, m_last_incoming_request);
if (may_timeout
&& !m_connecting
&& m_requests.empty()
&& m_reading_bytes == 0
| ||
relevance 2 | ../src/piece_picker.cpp:1966 | make the 2048 limit configurable |
make the 2048 limit configurable../src/piece_picker.cpp:1966 // only one of rarest_first or sequential can be set
void piece_picker::pick_pieces(bitfield const& pieces
, std::vector<piece_block>& interesting_blocks, int num_blocks
, int prefer_contiguous_blocks, void* peer
, int options, std::vector<int> const& suggested_pieces
, int num_peers
, counters& pc
) const
{
TORRENT_ASSERT(peer == 0 || static_cast<torrent_peer*>(peer)->in_use);
// 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;
}
// 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;
const std::vector<int> empty_vector;
// When prefer_contiguous_blocks is set (usually set when downloading from
| ||
relevance 2 | ../src/piece_picker.cpp:2575 | 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:2575 , 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(void* 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, void* 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:3360 | 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:3360 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/session_impl.cpp:216 | find a better place for this function |
find a better place for this function../src/session_impl.cpp:216 *j.vec, j.peer->make_write_handler(boost::bind(
&peer_connection::on_send_data, j.peer, _1, _2)));
}
else
{
if (j.recv_buf)
{
j.peer->get_socket()->async_read_some(asio::buffer(j.recv_buf, j.buf_size)
, j.peer->make_read_handler(boost::bind(
&peer_connection::on_receive_data, j.peer, _1, _2)));
}
else
{
j.peer->get_socket()->async_read_some(j.read_vec
, j.peer->make_read_handler(boost::bind(
&peer_connection::on_receive_data, j.peer, _1, _2)));
}
}
}
proxy_settings::proxy_settings(aux::session_settings const& sett)
{
hostname = sett.get_str(settings_pack::proxy_hostname);
username = sett.get_str(settings_pack::proxy_username);
password = sett.get_str(settings_pack::proxy_password);
type = sett.get_int(settings_pack::proxy_type);
port = sett.get_int(settings_pack::proxy_port);
proxy_hostnames = sett.get_bool(settings_pack::proxy_hostnames);
proxy_peer_connections = sett.get_bool(
settings_pack::proxy_peer_connections);
}
namespace aux {
void session_impl::init_peer_class_filter(bool unlimited_local)
{
// set the default peer_class_filter to use the local peer class
// for peers on local networks
boost::uint32_t lfilter = 1 << m_local_peer_class;
boost::uint32_t gfilter = 1 << m_global_class;
struct class_mapping
{
char const* first;
char const* last;
boost::uint32_t filter;
};
static const class_mapping v4_classes[] =
{
// everything
| ||
relevance 2 | ../src/session_impl.cpp:1813 | 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:1813 }
#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
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)
continue;
listen_socket_t s = setup_listener(device, address_family, port
, m_listen_port_retries, flags, ec);
if (ec == error_code(boost::system::errc::no_such_device, generic_category()))
{
++num_device_fails;
continue;
}
if (s.sock)
{
TORRENT_ASSERT(!m_abort);
| ||
relevance 2 | ../src/session_impl.cpp:1915 | use bind_to_device in udp_socket |
use bind_to_device in udp_socket../src/session_impl.cpp:1915 if (m_listen_port_retries > 0)
{
m_listen_interface.port(m_listen_interface.port() + 1);
--m_listen_port_retries;
goto retry;
}
if (m_alerts.should_post<listen_failed_alert>())
m_alerts.post_alert(listen_failed_alert(print_endpoint(m_listen_interface)
, listen_failed_alert::bind, ec, listen_failed_alert::udp));
return;
}
#ifdef TORRENT_USE_OPENSSL
int ssl_port = m_settings.get_int(settings_pack::ssl_listen);
// if ssl port is 0, we don't want to listen on an SSL port
if (ssl_port != 0)
{
udp::endpoint ssl_bind_if(m_listen_interface.address(), ssl_port);
m_ssl_udp_socket.bind(ssl_bind_if, ec);
if (ec)
{
#if defined TORRENT_LOGGING
session_log("SSL: cannot bind to UDP interface \"%s\": %s"
, print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
#endif
if (m_alerts.should_post<listen_failed_alert>())
{
error_code err;
m_alerts.post_alert(listen_failed_alert(print_endpoint(ssl_bind_if)
, listen_failed_alert::bind, ec, listen_failed_alert::utp_ssl));
}
ec.clear();
}
else
{
if (m_alerts.should_post<listen_succeeded_alert>())
m_alerts.post_alert(listen_succeeded_alert(
tcp::endpoint(ssl_bind_if.address(), ssl_bind_if.port())
, listen_succeeded_alert::utp_ssl));
}
}
#endif // TORRENT_USE_OPENSSL
| ||
relevance 2 | ../src/session_impl.cpp:1941 | use bind_to_device in udp_socket |
use bind_to_device in udp_socket../src/session_impl.cpp:1941 , print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
#endif
if (m_alerts.should_post<listen_failed_alert>())
{
error_code err;
m_alerts.post_alert(listen_failed_alert(print_endpoint(ssl_bind_if)
, listen_failed_alert::bind, ec, listen_failed_alert::utp_ssl));
}
ec.clear();
}
else
{
if (m_alerts.should_post<listen_succeeded_alert>())
m_alerts.post_alert(listen_succeeded_alert(
tcp::endpoint(ssl_bind_if.address(), ssl_bind_if.port())
, listen_succeeded_alert::utp_ssl));
}
}
#endif // TORRENT_USE_OPENSSL
m_udp_socket.bind(udp::endpoint(m_listen_interface.address(), m_listen_interface.port()), ec);
if (ec)
{
#if defined TORRENT_LOGGING
session_log("cannot bind to UDP interface \"%s\": %s"
, print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
#endif
if (m_listen_port_retries > 0)
{
m_listen_interface.port(m_listen_interface.port() + 1);
--m_listen_port_retries;
goto retry;
}
if (m_alerts.should_post<listen_failed_alert>())
{
error_code err;
m_alerts.post_alert(listen_failed_alert(print_endpoint(m_listen_interface)
, listen_failed_alert::bind, ec, listen_failed_alert::udp));
}
return;
}
else
{
m_external_udp_port = m_udp_socket.local_port();
maybe_update_udp_mapping(0, m_listen_interface.port(), m_listen_interface.port());
maybe_update_udp_mapping(1, m_listen_interface.port(), m_listen_interface.port());
if (m_alerts.should_post<listen_succeeded_alert>())
m_alerts.post_alert(listen_succeeded_alert(m_listen_interface, listen_succeeded_alert::udp));
}
if (m_settings.get_int(settings_pack::peer_tos) != 0)
| ||
relevance 2 | ../src/session_impl.cpp:3388 | 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:3388 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/torrent.cpp:719 | post alert |
post alert../src/torrent.cpp:719 state_updated();
set_state(torrent_status::downloading);
m_override_resume_data = true;
init();
}
#endif // if 0
void torrent::leave_seed_mode(bool seed)
{
if (!m_seed_mode) return;
if (!seed)
{
// this means the user promised we had all the
// files, but it turned out we didn't. This is
// an error.
#if defined TORRENT_LOGGING
debug_log("*** FAILED SEED MODE, rechecking");
#endif
}
#if defined TORRENT_LOGGING
debug_log("*** LEAVING SEED MODE (%s)", seed ? "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 (!seed)
{
m_have_all = false;
set_state(torrent_status::downloading);
force_recheck();
}
m_num_verified = 0;
m_verified.clear();
m_verifying.clear();
m_need_save_resume_data = true;
}
void torrent::verified(int piece)
{
TORRENT_ASSERT(piece < int(m_verified.size()));
TORRENT_ASSERT(piece >= 0);
TORRENT_ASSERT(m_verified.get_bit(piece) == false);
++m_num_verified;
| ||
relevance 2 | ../src/torrent.cpp:4729 | 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:4729 // files belonging to the torrents
disconnect_all(errors::torrent_aborted, peer_connection_interface::op_bittorrent);
// post a message to the main thread to destruct
// the torrent object from there
if (m_storage.get())
{
inc_refcount("release_files");
m_ses.disk_thread().async_stop_torrent(m_storage.get()
, boost::bind(&torrent::on_cache_flushed, shared_from_this(), _1));
}
else
{
TORRENT_ASSERT(m_abort);
if (alerts().should_post<cache_flushed_alert>())
alerts().post_alert(cache_flushed_alert(get_handle()));
}
m_storage.reset();
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;
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;
m_need_save_resume_data = true;
if (m_super_seeding) return;
// disable super seeding for all peers
for (peer_iterator i = begin(); i != end(); ++i)
{
(*i)->superseed_piece(-1, -1);
| ||
relevance 2 | ../src/torrent.cpp:4873 | the tracker login feature should probably be deprecated |
the tracker login feature should probably be deprecated../src/torrent.cpp:4873 if (alerts().should_post<file_renamed_alert>())
alerts().post_alert(file_renamed_alert(get_handle(), j->buffer, j->piece));
m_torrent_file->rename_file(j->piece, j->buffer);
}
else
{
if (alerts().should_post<file_rename_failed_alert>())
alerts().post_alert(file_rename_failed_alert(get_handle()
, j->piece, j->error.ec));
}
}
void torrent::on_torrent_paused(disk_io_job const* j)
{
TORRENT_ASSERT(is_single_thread());
if (alerts().should_post<torrent_paused_alert>())
alerts().post_alert(torrent_paused_alert(get_handle()));
}
std::string torrent::tracker_login() const
{
if (m_username.empty() && m_password.empty()) return "";
return m_username + ":" + m_password;
}
boost::uint32_t torrent::tracker_key() const
{
uintptr_t self = (uintptr_t)this;
uintptr_t ses = (uintptr_t)&m_ses;
sha1_hash h = hasher((char*)&self, sizeof(self))
.update((char*)&m_storage, sizeof(m_storage))
.update((char*)&ses, sizeof(ses))
.final();
unsigned char const* ptr = &h[0];
return detail::read_uint32(ptr);
}
void torrent::cancel_non_critical()
{
std::set<int> time_critical;
for (std::vector<time_critical_piece>::iterator i = m_time_critical_pieces.begin()
, end(m_time_critical_pieces.end()); i != end; ++i)
{
time_critical.insert(i->piece);
}
for (std::vector<peer_connection*>::iterator i
= m_connections.begin(), end(m_connections.end()); i != end; ++i)
{
// for each peer, go through its download and request queue
| ||
relevance 2 | ../src/torrent.cpp:7725 | if peer is a really good peer, maybe we shouldn't disconnect it |
if peer is a really good peer, maybe we shouldn't disconnect it../src/torrent.cpp:7725#if defined TORRENT_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())
{
peer->disconnect(errors::too_many_connections, peer_connection_interface::op_bittorrent);
p->peer_disconnected_other();
}
else
{
p->disconnect(errors::too_many_connections, peer_connection_interface::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
if (m_peer_list) m_peer_list->check_invariant();
#endif
if (m_share_mode)
recalc_share_mode();
return true;
}
bool torrent::want_tick() const
{
if (m_abort) return false;
if (!m_connections.empty()) return true;
| ||
relevance 2 | ../src/tracker_manager.cpp:196 | 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:196 , 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
, struct ip_filter& ipf
, aux::session_settings const& sett
#if defined TORRENT_LOGGING || TORRENT_USE_ASSERTS
, aux::session_logger& ses
#endif
)
: m_ip_filter(ipf)
, m_udp_socket(sock)
, m_host_resolver(resolver)
, m_settings(sett)
, m_stats_counters(stats_counters)
#if defined TORRENT_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);
}
| ||
relevance 2 | ../src/udp_tracker_connection.cpp:86 | support authentication here. tracker_req().auth |
support authentication here. tracker_req().auth../src/udp_tracker_connection.cpp:86 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/utp_stream.cpp:348 | 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:348 void incoming(boost::uint8_t const* buf, int size, packet* p, ptime 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, ptime 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:628 | 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:628 {
++m_num_responses;
if (m_parser.connection_close())
{
incoming_choke();
if (m_num_responses == 1)
m_web->supports_keepalive = false;
}
#ifdef TORRENT_LOGGING
peer_log("*** STATUS: %d %s", m_parser.status_code(), m_parser.message().c_str());
std::multimap<std::string, std::string> const& headers = m_parser.headers();
for (std::multimap<std::string, std::string>::const_iterator i = headers.begin()
, end(headers.end()); i != end; ++i)
peer_log(" %s: %s", i->first.c_str(), i->second.c_str());
#endif
// if the status code is not one of the accepted ones, abort
if (!is_ok_status(m_parser.status_code()))
{
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().post_alert(url_seed_alert(t->get_handle(), m_url
, error_msg));
}
received_bytes(0, bytes_transferred);
disconnect(error_code(m_parser.status_code(), get_http_category()), op_bittorrent, 1);
#ifdef TORRENT_DEBUG
TORRENT_ASSERT(statistics().last_payload_downloaded()
+ statistics().last_protocol_downloaded()
== dl_target);
#endif
return;
}
if (is_redirect(m_parser.status_code()))
{
// this means we got a redirection request
// look for the location header
std::string location = m_parser.header("location");
received_bytes(0, bytes_transferred);
if (location.empty())
{
// we should not try this server again.
t->remove_web_seed(this, errors::missing_location, op_bittorrent, 2);
| ||
relevance 2 | ../src/web_peer_connection.cpp:687 | 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:687 == dl_target);
#endif
return;
}
bool single_file_request = false;
if (!m_path.empty() && m_path[m_path.size() - 1] != '/')
single_file_request = true;
// add the redirected url and remove the current one
if (!single_file_request)
{
TORRENT_ASSERT(!m_file_requests.empty());
int file_index = m_file_requests.front();
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());
#ifdef TORRENT_DEBUG
TORRENT_ASSERT(statistics().last_payload_downloaded()
+ statistics().last_protocol_downloaded()
== dl_target);
#endif
return;
}
location.resize(i);
}
else
{
location = resolve_redirect_location(m_url, location);
}
#ifdef TORRENT_LOGGING
peer_log("*** 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);
| ||
relevance 2 | ../src/kademlia/node.cpp:67 | make this configurable in dht_settings |
make this configurable in dht_settings../src/kademlia/node.cpp:67#include "libtorrent/kademlia/routing_table.hpp"
#include "libtorrent/kademlia/node.hpp"
#include "libtorrent/kademlia/dht_observer.hpp"
#include "libtorrent/kademlia/refresh.hpp"
#include "libtorrent/kademlia/get_peers.hpp"
#include "libtorrent/kademlia/get_item.hpp"
#include "libtorrent/performance_counters.hpp" // for counters
#ifdef TORRENT_USE_VALGRIND
#include <valgrind/memcheck.h>
#endif
namespace libtorrent { namespace dht
{
void incoming_error(entry& e, char const* msg, int error_code = 203);
using detail::write_endpoint;
enum { announce_interval = 30 };
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(node)
#endif
// remove peers that have timed out
void purge_peers(std::set<peer_entry>& peers)
{
for (std::set<peer_entry>::iterator i = peers.begin()
, end(peers.end()); i != end;)
{
// the peer has timed out
if (i->added + minutes(int(announce_interval * 1.5f)) < time_now())
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(node) << "peer timed out at: " << i->addr;
#endif
peers.erase(i++);
}
else
++i;
}
}
void nop() {}
node_impl::node_impl(alert_dispatcher* alert_disp
, udp_socket_interface* sock
, dht_settings const& settings, node_id nid, address const& external_address
, dht_observer* observer
| ||
relevance 2 | ../src/kademlia/node.cpp:491 | 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:491 // 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_impl::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 || TORRENT_RELEASE_ASSERTS
o->m_in_constructor = false;
#endif
entry e;
e["y"] = "q";
entry& a = e["a"];
// 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);
// e["q"] = "find_node";
// a["target"] = target.to_string();
m_rpc.invoke(e, ep, o);
}
time_duration node_impl::connection_timeout()
{
time_duration d = m_rpc.tick();
| ||
relevance 2 | ../src/kademlia/node.cpp:581 | use the non deprecated function instead of this one |
use the non deprecated function instead of this one../src/kademlia/node.cpp:581 return d;
}
void node_impl::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& l = requests.back();
(*i)->status(l);
}
}
#ifndef TORRENT_NO_DEPRECATE
void node_impl::status(session_status& s)
{
mutex_t::scoped_lock l(m_mutex);
m_table.status(s);
s.dht_torrents = int(m_map.size());
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& l = s.active_requests.back();
(*i)->status(l);
}
}
#endif
void node_impl::lookup_peers(sha1_hash const& info_hash, entry& reply
, bool noseed, bool scrape) const
{
if (m_post_alert)
{
alert* a = new dht_get_peers_alert(info_hash);
if (!m_post_alert->post_alert(a)) delete a;
}
table_t::const_iterator i = m_map.lower_bound(info_hash);
if (i == m_map.end()) return;
if (i->first != info_hash) return;
| ||
relevance 2 | ../src/kademlia/node.cpp:909 | find_node should write directly to the response entry |
find_node should write directly to the response entry../src/kademlia/node.cpp:909 TORRENT_LOG(node) << " values: " << reply["values"].list().size();
}
#endif
}
else if (strcmp(query, "find_node") == 0)
{
key_desc_t msg_desc[] = {
{"target", lazy_entry::string_t, 20, 0},
};
lazy_entry const* msg_keys[1];
if (!verify_message(arg_ent, msg_desc, msg_keys, 1, 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 (strcmp(query, "announce_peer") == 0)
{
key_desc_t msg_desc[] = {
{"info_hash", lazy_entry::string_t, 20, 0},
{"port", lazy_entry::int_t, 0, 0},
{"token", lazy_entry::string_t, 0, 0},
{"n", lazy_entry::string_t, 0, key_desc_t::optional},
{"seed", lazy_entry::int_t, 0, key_desc_t::optional},
{"implied_port", lazy_entry::int_t, 0, key_desc_t::optional},
};
lazy_entry const* msg_keys[6];
if (!verify_message(arg_ent, msg_desc, msg_keys, 6, 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:110 | use the non deprecated function instead of this one |
use the non deprecated function instead of this one../src/kademlia/routing_table.cpp:110
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()
, end(i->live_nodes.end()); k != end; ++k)
| ||
relevance 2 | ../src/kademlia/routing_table.cpp:900 | move the lowest priority nodes to the replacement bucket |
move the lowest priority nodes to the replacement bucket../src/kademlia/routing_table.cpp:900 bucket_t& b = m_buckets[bucket_index].live_nodes;
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 new_bucket_size = bucket_limit(bucket_index + 1);
for (bucket_t::iterator j = b.begin(); j != b.end();)
{
if (distance_exp(m_id, j->id) >= 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/enum_net.hpp:137 | 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:137
address ip = address::from_string(device_name, ec);
if (!ec)
{
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() != ipv4)
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 true if the given device exists
TORRENT_EXTRA_EXPORT bool has_interface(char const* name, io_service& ios
| ||
relevance 2 | ../include/libtorrent/piece_picker.hpp:599 | 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:599 // the number of peers that has this piece
// (availability)
#if 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_downloadin.
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
#if 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 void*> 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.
#if TORRENT_OPTIMIZE_MEMORY_USAGE
we_have_index = 0x3ffff,
#else
| ||
relevance 2 | ../include/libtorrent/proxy_base.hpp:257 | 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:257 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);
stream_socket m_sock;
std::string m_hostname;
int m_port;
endpoint_type m_remote_endpoint;
tcp::resolver m_resolver;
};
}
#endif
| ||
relevance 2 | ../include/libtorrent/session.hpp:271 | the ip filter should probably be saved here too |
the ip filter should probably be saved here too../include/libtorrent/session.hpp:271
if ((flags & start_default_features) == 0)
{
pack.set_bool(settings_pack::enable_upnp, false);
pack.set_bool(settings_pack::enable_natpmp, false);
pack.set_bool(settings_pack::enable_lsd, false);
pack.set_bool(settings_pack::enable_dht, false);
}
init();
start(flags, pack);
}
// The destructor of session will notify all trackers that our torrents
// have been shut down. If some trackers are down, they will time out.
// All this before the destructor of session returns. So, it's advised
// that any kind of interface (such as windows) are closed before
// destructing the session object. Because it can take a few second for
// it to finish. The timeout can be set with apply_settings().
~session();
// 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 session_settings)
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,
// internal
save_as_map = 0x040,
// saves RSS feeds
save_feeds = 0x080
#ifndef TORRENT_NO_DEPRECATE
,
save_proxy = 0x008,
save_i2p_proxy = 0x010,
save_dht_proxy = save_proxy,
save_peer_proxy = save_proxy,
save_web_proxy = save_proxy,
| ||
relevance 2 | ../include/libtorrent/session_settings.hpp:55 | this type is only used internally now. move it to an internal header and make this type properly deprecated. |
this type is only used internally now. move it to an internal
header and make this type properly deprecated.../include/libtorrent/session_settings.hpp:55
#include "libtorrent/version.hpp"
#include "libtorrent/config.hpp"
#include <boost/cstdint.hpp>
#include <string>
#include <vector>
#include <utility>
namespace libtorrent
{
#ifndef TORRENT_NO_DEPRECATE
#define TORRENT_EXPORT_DEPRECATED TORRENT_EXPORT
#else
#define TORRENT_EXPORT_DEPRECATED
#endif
namespace aux { struct session_settings; }
// The ``proxy_settings`` structs contains the information needed to
// direct certain traffic to a proxy.
struct TORRENT_EXPORT_DEPRECATED proxy_settings
{
// defaults constructs proxy settings, initializing it to the default
// settings.
proxy_settings() : type(0)
, port(0), proxy_hostnames(true)
, proxy_peer_connections(true)
{}
// construct the proxy_settings object from the settings
// this constructor is implemented in session_impl.cpp
proxy_settings(aux::session_settings const& sett);
// the name or IP of the proxy server. ``port`` is the port number the
// proxy listens to. If required, ``username`` and ``password`` can be
// set to authenticate with the proxy.
std::string hostname;
// when using a proy type that requires authentication, the username
// and password fields must be set to the credentials for the proxy.
std::string username;
std::string password;
#ifndef TORRENT_NO_DEPRECATE
// the type of proxy to use. Assign one of these to the
// proxy_settings::type field.
enum proxy_type
{
| ||
relevance 2 | ../include/libtorrent/socks5_stream.hpp:131 | 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:131 if (m_dst_name.size() > 255)
m_dst_name.resize(255);
}
void close(error_code& ec)
{
m_hostname.clear();
m_dst_name.clear();
proxy_base::close(ec);
}
#ifndef BOOST_NO_EXCEPTIONS
void close()
{
m_hostname.clear();
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(m_command == socks5_bind
|| 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:278 | 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:278 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
ptime m_start_time;
// this is set every time something is received
ptime 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_interface.hpp:130 | 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:130#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
};
#endif // TORRENT_LOGGING || TORRENT_USE_ASSERTS
// TOOD: 2 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.
struct session_interface
: buffer_allocator_interface
#if defined TORRENT_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:155 | remove this. There's already get_resolver() |
remove this. There's already get_resolver()../include/libtorrent/aux_/session_interface.hpp:155 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;
// ip and port filter
virtual ip_filter& get_ip_filter() = 0;
virtual port_filter const& get_port_filter() const = 0;
virtual boost::int64_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:210 | 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:210 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;
| ||
relevance 1 | ../src/disk_io_thread.cpp:233 | 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:233 std::pair<block_cache::iterator, block_cache::iterator> pieces
= m_disk_cache.all_pieces();
TORRENT_ASSERT(pieces.first == pieces.second);
#endif
#ifdef TORRENT_DISK_STATS
if (g_access_log)
{
FILE* f = g_access_log;
g_access_log = NULL;
fclose(f);
}
#endif
TORRENT_ASSERT(m_magic == 0x1337);
#if TORRENT_USE_ASSERTS
m_magic = 0xdead;
#endif
}
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;
// 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))));
}
}
else
{
while (m_num_threads > i) { --m_num_threads; }
mutex::scoped_lock l(m_job_mutex);
m_job_cond.notify_all();
m_hash_job_cond.notify_all();
l.unlock();
if (wait) for (int i = m_num_threads; i < m_threads.size(); ++i) m_threads[i]->join();
// this will detach the threads
m_threads.resize(m_num_threads);
}
}
| ||
relevance 1 | ../src/http_seed_connection.cpp:124 | 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:124 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:5210 | 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:5210 void session_impl::on_port_mapping(int mapping, address const& ip, int port
, 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.post_alert(portmap_alert(mapping, port
, map_transport));
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.post_alert(portmap_alert(mapping, port
, map_transport));
return;
}
if (ec)
{
if (m_alerts.should_post<portmap_error_alert>())
m_alerts.post_alert(portmap_error_alert(mapping
, map_transport, ec));
}
else
{
if (m_alerts.should_post<portmap_alert>())
m_alerts.post_alert(portmap_alert(mapping, port
, map_transport));
}
}
#ifndef TORRENT_NO_DEPRECATE
session_status session_impl::status() const
{
// INVARIANT_CHECK;
| ||
relevance 1 | ../src/session_impl.cpp:6412 | we only need to do this if our global IPv4 address has changed since the DHT (currently) only supports IPv4. Since restarting the DHT is kind of expensive, it would be nice to not do it unnecessarily |
we only need to do this if our global IPv4 address has changed
since the DHT (currently) only supports IPv4. Since restarting the DHT
is kind of expensive, it would be nice to not do it unnecessarily../src/session_impl.cpp:6412#endif
if (!m_external_ip.cast_vote(ip, source_type, source)) return;
#if defined TORRENT_LOGGING
session_log(" external IP updated");
#endif
if (m_alerts.should_post<external_ip_alert>())
m_alerts.post_alert(external_ip_alert(ip));
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{
i->second->new_external_ip();
}
// since we have a new external IP now, we need to
// restart the DHT with a new node ID
#ifndef TORRENT_DISABLE_DHT
if (m_dht)
{
entry s = m_dht->state();
int cur_state = 0;
int prev_state = 0;
entry* nodes1 = s.find_key("nodes");
if (nodes1 && nodes1->type() == entry::list_t) cur_state = nodes1->list().size();
entry* nodes2 = m_dht_state.find_key("nodes");
if (nodes2 && nodes2->type() == entry::list_t) prev_state = nodes2->list().size();
if (cur_state > prev_state) m_dht_state = s;
start_dht(m_dht_state);
}
#endif
}
// decrement the refcount of the block in the disk cache
// since the network thread doesn't need it anymore
void session_impl::reclaim_block(block_cache_reference ref)
{
m_disk_thread.reclaim_block(ref);
}
char* session_impl::allocate_disk_buffer(char const* category)
{
return m_disk_thread.allocate_disk_buffer(category);
}
char* session_impl::async_allocate_disk_buffer(char const* category
, boost::function<void(char*)> const& handler)
{
return m_disk_thread.async_allocate_disk_buffer(category, handler);
| ||
relevance 1 | ../src/torrent.cpp:1157 | 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:1157 alerts().post_alert(file_error_alert(j->error.ec
, resolve_filename(j->error.file), j->error.operation_str(), get_handle()));
// put the torrent in an error-state
set_error(j->error.ec, j->error.file);
// 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;
}
// 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)
{
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;
p->update_interest();
if (!m_abort)
{
if (request_a_block(*this, *p))
inc_stats_counter(counters::hash_fail_piece_picks);
p->send_block_requests();
}
}
| ||
relevance 1 | ../src/torrent.cpp:6877 | 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:6877 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->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
// byte is a bitmask representing different properties
| ||
relevance 1 | ../src/torrent.cpp:7970 | 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:7970 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)
{
peer_connection* p = *i;
TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
if (p->upload_only())
{
#if defined TORRENT_LOGGING
p->peer_log("*** SEED, CLOSING CONNECTION");
#endif
seeds.push_back(p);
}
}
std::for_each(seeds.begin(), seeds.end()
, boost::bind(&peer_connection::disconnect, _1, errors::torrent_finished
, peer_connection_interface::op_bittorrent, 0));
}
if (m_abort) return;
update_want_peers();
TORRENT_ASSERT(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));
// this torrent just completed downloads, which means it will fall
| ||
relevance 1 | ../include/libtorrent/ip_voter.hpp:122 | 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:122 // away all the votes and started from scratch, in case
// our IP has changed
ptime 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 1 | ../include/libtorrent/web_peer_connection.hpp:122 | if we make this be a disk_buffer_holder instead we would save a copy sometimes 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 sometimes
use allocate_disk_receive_buffer and release_disk_receive_buffer../include/libtorrent/web_peer_connection.hpp:122
// returns the block currently being
// downloaded. And the progress of that
// block. If the peer isn't downloading
// a piece for the moment, the boost::optional
// will be invalid.
boost::optional<piece_block_progress> downloading_piece_progress() const;
void handle_padfile(buffer::const_interval& recv_buffer);
// this has one entry per http-request
// (might be more than the bt requests)
std::deque<int> m_file_requests;
std::string m_url;
web_seed_t* m_web;
// this is used for intermediate storage of pieces
// that are received in more than one HTTP response
std::vector<char> m_piece;
// the number of bytes received in the current HTTP
// response. used to know where in the buffer the
// next response starts
boost::int64_t m_received_body;
// position in the current range response
boost::int64_t m_range_pos;
// 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
boost::int64_t m_chunk_pos;
// the position in the current block
int m_block_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;
};
}
| ||
relevance 0 | ../test/test_block_cache.cpp:475 | test try_evict_blocks |
test try_evict_blocks../test/test_block_cache.cpp:475 | ||
relevance 0 | ../test/test_block_cache.cpp:476 | test evicting volatile pieces, to see them be removed |
test evicting volatile pieces, to see them be removed../test/test_block_cache.cpp:476 | ||
relevance 0 | ../test/test_block_cache.cpp:477 | test evicting dirty pieces |
test evicting dirty pieces../test/test_block_cache.cpp:477 | ||
relevance 0 | ../test/test_block_cache.cpp:478 | test free_piece |
test free_piece../test/test_block_cache.cpp:478 | ||
relevance 0 | ../test/test_block_cache.cpp:479 | test abort_dirty |
test abort_dirty../test/test_block_cache.cpp:479 | ||
relevance 0 | ../test/test_block_cache.cpp:480 | test unaligned reads |
test unaligned reads../test/test_block_cache.cpp:480 // it's supposed to be a cache hit
TEST_CHECK(ret >= 0);
// return the reference to the buffer we just read
RETURN_BUFFER;
tailqueue jobs;
bc.clear(jobs);
}
int test_main()
{
test_write();
test_flush();
test_insert();
test_evict();
test_arc_promote();
test_arc_unghost();
test_iovec();
test_unaligned_read();
return 0;
}
| ||
relevance 0 | ../test/test_dht.cpp:436 | test obfuscated_get_peers |
test obfuscated_get_peers../test/test_dht.cpp:436 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;
bool get_item_cb(dht::item& i)
{
if (!i.empty())
g_got_items.push_back(i);
if (!g_put_item.empty())
{
i = g_put_item;
g_put_count++;
return true;
}
return false;
}
int test_main()
{
dht_settings sett;
sett.max_torrents = 4;
sett.max_dht_items = 4;
sett.enforce_node_id = false;
address ext = address::from_string("236.0.0.1");
mock_socket s;
print_alert ad;
counters cnt;
dht::node_impl node(&ad, &s, sett, node_id(0), ext, 0, cnt);
// DHT should be running on port 48199 now
lazy_entry response;
lazy_entry const* parsed[11];
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, "10");
dht::key_desc_t pong_desc[] = {
{"y", lazy_entry::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child},
};
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, pong_desc, parsed, 4, error_string, sizeof(error_string));
| ||
relevance 0 | ../test/test_metadata_extension.cpp:91 | it would be nice to test reversing which session is making the connection as well |
it would be nice to test reversing
which session is making the connection as well../test/test_metadata_extension.cpp:91 , int timeout)
{
using namespace libtorrent;
namespace lt = libtorrent;
fprintf(stderr, "\n==== test transfer: timeout=%d %s%s%s%s%s%s ====\n\n"
, timeout
, (flags & clear_files) ? "clear-files " : ""
, (flags & disconnect) ? "disconnect " : ""
, (flags & full_encryption) ? "encryption " : ""
, (flags & reverse) ? "reverse " : ""
, (flags & utp) ? "utp " : ""
, (flags & upload_only) ? "upload_only " : "");
// these are declared before the session objects
// so that they are destructed last. This enables
// the sessions to destruct in parallel
session_proxy p1;
session_proxy p2;
lt::session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000), "0.0.0.0", 0);
lt::session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000), "0.0.0.0", 0);
ses1.add_extension(constructor);
ses2.add_extension(constructor);
torrent_handle tor1;
torrent_handle tor2;
settings_pack pack;
pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced);
pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced);
pack.set_bool(settings_pack::prefer_rc4, flags & full_encryption);
if (flags & utp)
{
pack.set_bool(settings_pack::utp_dynamic_sock_buf, true);
pack.set_bool(settings_pack::enable_incoming_utp, true);
pack.set_bool(settings_pack::enable_outgoing_utp, true);
pack.set_bool(settings_pack::enable_incoming_tcp, false);
pack.set_bool(settings_pack::enable_outgoing_tcp, false);
}
else
{
pack.set_bool(settings_pack::enable_incoming_utp, false);
pack.set_bool(settings_pack::enable_outgoing_utp, false);
pack.set_bool(settings_pack::enable_incoming_tcp, true);
pack.set_bool(settings_pack::enable_outgoing_tcp, true);
}
ses1.apply_settings(pack);
ses2.apply_settings(pack);
| ||
relevance 0 | ../test/test_peer_list.cpp:581 | test erasing peers |
test erasing peers../test/test_peer_list.cpp:581 | ||
relevance 0 | ../test/test_peer_list.cpp:582 | test logic for which connection to keep when receiving an incoming connection to the same peer as we just made an outgoing connection to |
test logic for which connection to keep when receiving an incoming
connection to the same peer as we just made an outgoing connection to../test/test_peer_list.cpp:582 | ||
relevance 0 | ../test/test_peer_list.cpp:584 | 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:584 | ||
relevance 0 | ../test/test_peer_list.cpp:585 | test add i2p peers |
test add i2p peers../test/test_peer_list.cpp:585 | ||
relevance 0 | ../test/test_peer_list.cpp:586 | test allow_i2p_mixed |
test allow_i2p_mixed../test/test_peer_list.cpp:586 | ||
relevance 0 | ../test/test_peer_list.cpp:587 | test insert_peer failing with all error conditions |
test insert_peer failing with all error conditions../test/test_peer_list.cpp:587 | ||
relevance 0 | ../test/test_peer_list.cpp:588 | test IPv6 |
test IPv6../test/test_peer_list.cpp:588 | ||
relevance 0 | ../test/test_peer_list.cpp:589 | test connect_to_peer() failing |
test connect_to_peer() failing../test/test_peer_list.cpp:589 | ||
relevance 0 | ../test/test_peer_list.cpp:590 | test connection_closed |
test connection_closed../test/test_peer_list.cpp:590 TEST_EQUAL(p.num_peers(), 2);
TEST_EQUAL(p.num_connect_candidates(), 2);
TEST_EQUAL(p.has_peer(peer1), true);
TEST_EQUAL(p.has_peer(peer2), true);
ip_filter filter;
filter.add_rule(address_v4::from_string("10.10.0.1")
, address_v4::from_string("10.10.0.1"), ip_filter::blocked);
p.apply_ip_filter(filter, &st, banned);
TEST_EQUAL(st.erased.size(), 1);
st.erased.clear();
TEST_EQUAL(p.num_peers(), 1);
TEST_EQUAL(p.num_connect_candidates(), 1);
TEST_EQUAL(p.has_peer(peer1), false);
TEST_EQUAL(p.has_peer(peer2), true);
}
return 0;
}
| ||
relevance 0 | ../test/test_primitives.cpp:213 | 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_primitives.cpp:213 | ||
relevance 0 | ../test/test_primitives.cpp:214 | 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_primitives.cpp:214 TEST_CHECK(!filter.find(k3));
TEST_CHECK(filter.find(k4));
// test timestamp_history
{
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);
}
// test error codes
TEST_CHECK(error_code(errors::http_error).message() == "HTTP error");
TEST_CHECK(error_code(errors::missing_file_sizes).message() == "missing or invalid 'file sizes' entry");
TEST_CHECK(error_code(errors::unsupported_protocol_version).message() == "unsupported protocol version");
TEST_CHECK(error_code(errors::no_i2p_router).message() == "no i2p router is set up");
TEST_CHECK(error_code(errors::http_parse_error).message() == "Invalid HTTP header");
TEST_CHECK(error_code(errors::error_code_max).message() == "Unknown error");
TEST_CHECK(error_code(errors::unauthorized, get_http_category()).message() == "401 Unauthorized");
TEST_CHECK(error_code(errors::service_unavailable, get_http_category()).message() == "503 Service Unavailable");
// test snprintf
char msg[10];
snprintf(msg, sizeof(msg), "too %s format string", "long");
TEST_CHECK(strcmp(msg, "too long ") == 0);
std::string path;
sanitize_append_path_element(path, "a...", 4);
TEST_EQUAL(path, "a");
path.clear();
sanitize_append_path_element(path, "a ", 4);
TEST_EQUAL(path, "a");
path.clear();
sanitize_append_path_element(path, "a...b", 5);
TEST_EQUAL(path, "a...b");
| ||
relevance 0 | ../test/test_resume.cpp:340 | 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:340 // resume data overrides the paused flag
fprintf(stderr, "flags: paused\n");
s = test_resume_flags(add_torrent_params::flag_paused);
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);
return 0;
}
| ||
relevance 0 | ../test/test_rss.cpp:135 | verify some key state is saved in 'state' |
verify some key state is saved in 'state'../test/test_rss.cpp:135 feed_status st;
f->get_feed_status(&st);
TEST_CHECK(!st.error);
print_feed(st);
TEST_CHECK(st.items.size() == expect.num_items);
if (st.items.size() > 0)
{
TEST_CHECK(st.items[0].url == expect.first_url);
TEST_CHECK(st.items[0].size == expect.first_size);
TEST_CHECK(st.items[0].title == expect.first_title);
}
entry state;
f->save_state(state);
fprintf(stderr, "feed_state:\n");
std::cerr << state.to_string() << "\n";
}
int test_main()
{
std::string root_dir = parent_path(current_working_directory());
test_feed(combine_path(root_dir, "eztv.xml"), rss_expect(30, "http://torrent.zoink.it/The.Daily.Show.2012.02.16.(HDTV-LMAO)[VTV].torrent", "The Daily Show 2012-02-16 [HDTV - LMAO]", 183442338));
test_feed(combine_path(root_dir, "cb.xml"), rss_expect(50, "http://www.clearbits.net/get/1911-norbergfestival-2011.torrent", "Norbergfestival 2011", 1160773632));
test_feed(combine_path(root_dir, "kat.xml"), rss_expect(25, "http://kat.ph/torrents/benito-di-paula-1975-benito-di-paula-lp-rip-ogg-at-500-jarax4u-t6194897/", "Benito Di Paula - 1975 - Benito Di Paula (LP Rip OGG at 500) [jarax4u]", 168773863));
test_feed(combine_path(root_dir, "mn.xml"), rss_expect(20, "http://www.mininova.org/get/13203100", "Dexcell - January TwentyTwelve Mix", 137311179));
test_feed(combine_path(root_dir, "pb.xml"), rss_expect(60, "magnet:?xt=urn:btih:FD4CDDB7BBE722D17A018EFD875EB0695ED7159C&dn=Thompson+Twins+-+1989+-+Big+Trash+%5BMP3%5D", "Thompson Twins - 1989 - Big Trash [MP3]", 100160904));
test_feed(combine_path(root_dir, "fg.xml"), rss_expect(15, "http://torrage.com/torrent/470BCD2007011E9F31556B36E199D03D948A1A52.torrent", "Top.Gear.S20E04.1080i.ts", -1));
return 0;
}
| ||
relevance 0 | ../test/test_ssl.cpp:377 | 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:377 // 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:475 | 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:475 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, libtorrent::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, libtorrent::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_torrent.cpp:133 | wait for an alert rather than just waiting 10 seconds. This is kind of silly |
wait for an alert rather than just waiting 10 seconds. This is kind of silly../test/test_torrent.cpp:133 TEST_EQUAL(h.file_priorities().size(), info->num_files());
TEST_EQUAL(h.file_priorities()[0], 0);
if (info->num_files() > 1)
TEST_EQUAL(h.file_priorities()[1], 0);
if (info->num_files() > 2)
TEST_EQUAL(h.file_priorities()[2], 1);
}
}
if (info->num_pieces() > 0)
{
h.piece_priority(0, 1);
st = h.status();
TEST_CHECK(st.pieces.size() > 0 && st.pieces[0] == false);
std::vector<char> piece(info->piece_length());
for (int i = 0; i < int(piece.size()); ++i)
piece[i] = (i % 26) + 'A';
h.add_piece(0, &piece[0]);
// wait until the piece is done writing and hashing
test_sleep(2000);
st = h.status();
TEST_CHECK(st.pieces.size() > 0 && st.pieces[0] == true);
std::cout << "reading piece 0" << std::endl;
h.read_piece(0);
alert const* a = ses.wait_for_alert(seconds(10));
bool passed = false;
while (a)
{
std::auto_ptr<alert> al = ses.pop_alert();
assert(al.get());
std::cout << " " << al->message() << std::endl;
if (read_piece_alert* rpa = alert_cast<read_piece_alert>(al.get()))
{
std::cout << "SUCCEEDED!" << std::endl;
passed = true;
TEST_CHECK(memcmp(&piece[0], rpa->buffer.get(), piece.size()) == 0);
TEST_CHECK(rpa->size == info->piece_size(0));
TEST_CHECK(rpa->piece == 0);
TEST_CHECK(hasher(&piece[0], piece.size()).final() == info->hash_for_piece(0));
break;
}
a = ses.wait_for_alert(seconds(10));
TEST_CHECK(a);
}
TEST_CHECK(passed);
}
}
int test_main()
| ||
relevance 0 | ../test/test_torrent_parse.cpp:116 | test remap_files |
test remap_files../test/test_torrent_parse.cpp:116 | ||
relevance 0 | ../test/test_torrent_parse.cpp:117 | 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_parse.cpp:117 | ||
relevance 0 | ../test/test_torrent_parse.cpp:118 | torrent with 'p' (padfile) attribute |
torrent with 'p' (padfile) attribute../test/test_torrent_parse.cpp:118 | ||
relevance 0 | ../test/test_torrent_parse.cpp:119 | torrent with 'h' (hidden) attribute |
torrent with 'h' (hidden) attribute../test/test_torrent_parse.cpp:119 | ||
relevance 0 | ../test/test_torrent_parse.cpp:120 | torrent with 'x' (executable) attribute |
torrent with 'x' (executable) attribute../test/test_torrent_parse.cpp:120 | ||
relevance 0 | ../test/test_torrent_parse.cpp:121 | torrent with 'l' (symlink) attribute |
torrent with 'l' (symlink) attribute../test/test_torrent_parse.cpp:121 | ||
relevance 0 | ../test/test_torrent_parse.cpp:122 | creating a merkle torrent (torrent_info::build_merkle_list) |
creating a merkle torrent (torrent_info::build_merkle_list)../test/test_torrent_parse.cpp:122 | ||
relevance 0 | ../test/test_torrent_parse.cpp:123 | 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_parse.cpp:123 { "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_missing_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 },
};
namespace libtorrent
{
// defined in torrent_info.cpp
TORRENT_EXPORT bool verify_encoding(std::string& target, bool path = true);
TORRENT_EXTRA_EXPORT void sanitize_append_path_element(std::string& p, char const* element, int len);
}
int test_main()
{
error_code ec;
// test merkle_*() functions
// this is the structure:
// 0
// 1 2
// 3 4 5 6
// 7 8 9 10 11 12 13 14
// num_leafs = 8
TEST_EQUAL(merkle_num_leafs(1), 1);
TEST_EQUAL(merkle_num_leafs(2), 2);
TEST_EQUAL(merkle_num_leafs(3), 4);
TEST_EQUAL(merkle_num_leafs(4), 4);
TEST_EQUAL(merkle_num_leafs(5), 8);
TEST_EQUAL(merkle_num_leafs(6), 8);
TEST_EQUAL(merkle_num_leafs(7), 8);
TEST_EQUAL(merkle_num_leafs(8), 8);
TEST_EQUAL(merkle_num_leafs(9), 16);
TEST_EQUAL(merkle_num_leafs(10), 16);
TEST_EQUAL(merkle_num_leafs(11), 16);
TEST_EQUAL(merkle_num_leafs(12), 16);
TEST_EQUAL(merkle_num_leafs(13), 16);
TEST_EQUAL(merkle_num_leafs(14), 16);
TEST_EQUAL(merkle_num_leafs(15), 16);
TEST_EQUAL(merkle_num_leafs(16), 16);
TEST_EQUAL(merkle_num_leafs(17), 32);
| ||
relevance 0 | ../test/test_tracker.cpp:198 | test parse peers6 |
test parse peers6../test/test_tracker.cpp:198 | ||
relevance 0 | ../test/test_tracker.cpp:199 | test parse tracker-id |
test parse tracker-id../test/test_tracker.cpp:199 | ||
relevance 0 | ../test/test_tracker.cpp:200 | test parse failure-reason |
test parse failure-reason../test/test_tracker.cpp:200 | ||
relevance 0 | ../test/test_tracker.cpp:201 | 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:201 TEST_EQUAL(ec, error_code());
TEST_EQUAL(resp.peers.size(), 0);
TEST_EQUAL(resp.external_ip, address_v6::from_string("f102:0304::ffff"));
}
#endif
int test_main()
{
test_parse_hostname_peers();
test_parse_peers4();
test_parse_interval();
test_parse_warning();
test_parse_failure_reason();
test_parse_scrape_response();
test_parse_scrape_response_with_zero();
test_parse_external_ip();
#if TORRENT_USE_IPV6
test_parse_external_ip6();
#endif
int http_port = start_web_server();
int udp_port = start_udp_tracker();
int prev_udp_announces = num_udp_announces();
int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;
lt::session* s = new lt::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);
settings_pack pack;
#ifndef TORRENT_NO_DEPRECATE
pack.set_int(settings_pack::half_open_limit, 1);
#endif
pack.set_bool(settings_pack::announce_to_all_trackers, true);
pack.set_bool(settings_pack::announce_to_all_tiers, true);
s->apply_settings(pack);
error_code ec;
remove_all("tmp1_tracker", ec);
create_directory("tmp1_tracker", ec);
std::ofstream file(combine_path("tmp1_tracker", "temporary").c_str());
boost::shared_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
file.close();
char tracker_url[200];
snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
t->add_tracker(tracker_url, 0);
| ||
relevance 0 | ../test/test_transfer.cpp:288 | 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:288 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);
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);
fprintf(stderr, "%s: discovered disk full mode. Raise limit and disable upload-mode\n", time_now_string());
peer_disconnects = 0;
continue;
| ||
relevance 0 | ../test/test_upnp.cpp:100 | 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:100 "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, error_code const& err)
{
callback_info info = {mapping, port, err};
callbacks.push_back(info);
std::cerr << "mapping: " << mapping << ", port: " << port << ", IP: " << ip
<< ", error: \"" << err.message() << "\"\n";
}
int run_upnp_test(char const* root_filename, char const* router_model, char const* control_name)
{
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 | ../test/web_seed_suite.cpp:366 | file hashes don't work with the new torrent creator reading async |
file hashes don't work with the new torrent creator reading async../test/web_seed_suite.cpp:366 // corrupt the files now, so that the web seed will be banned
if (test_url_seed)
{
create_random_files(combine_path(save_path, "torrent_dir"), file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0]));
}
else
{
piece_size = 64 * 1024;
char* random_data = (char*)malloc(64 * 1024 * num_pieces);
std::generate(random_data, random_data + 64 * 1024 * num_pieces, random_byte);
save_file(combine_path(save_path, "seed").c_str(), random_data, 64 * 1024 * num_pieces);
free(random_data);
}
}
std::vector<char> buf;
bencode(std::back_inserter(buf), t.generate());
boost::shared_ptr<torrent_info> torrent_file(boost::make_shared<torrent_info>(&buf[0], buf.size(), boost::ref(ec), 0));
/*
// no point in testing the hashes since we know the data is corrupt
if (!test_ban)
{
// verify that the file hashes are correct
for (int i = 0; i < torrent_file->num_files(); ++i)
{
sha1_hash h1 = torrent_file->file_at(i).filehash;
sha1_hash h2 = file_hash(combine_path(save_path
, torrent_file->file_at(i).path));
// fprintf(stderr, "%s: %s == %s\n"
// , torrent_file->file_at(i).path.c_str()
// , to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str());
TEST_EQUAL(h1, h2);
}
}
*/
{
settings_pack pack;
pack.set_int(settings_pack::max_queued_disk_bytes, 256 * 1024);
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:51000");
pack.set_int(settings_pack::max_retry_port_bind, 1000);
pack.set_int(settings_pack::alert_mask, ~(alert::progress_notification | alert::stats_notification));
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);
libtorrent::session ses(pack, 0);
test_transfer(ses, torrent_file, proxy, port, protocol, test_url_seed
, chunked_encoding, test_ban, keepalive);
| ||
relevance 0 | ../src/block_cache.cpp:884 | 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:884 }
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 i = lru_list[end]->iterate(); i.get() && num > 0;)
{
cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get());
TORRENT_PIECE_ASSERT(pe->in_use, pe);
i.next();
if (pe == ignore)
continue;
if (pe->ok_to_evict())
{
#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
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:948 | this should probably only be done every n:th time |
this should probably only be done every n:th time../src/block_cache.cpp:948 }
if (pe->ok_to_evict())
{
#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 i = m_lru[cached_piece_entry::write_lru].iterate(); i.get() && num > 0;)
{
cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get());
TORRENT_PIECE_ASSERT(pe->in_use, pe);
i.next();
if (pe == ignore)
continue;
if (pe->ok_to_evict())
{
#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:1693 | create a holder for refcounts that automatically decrement |
create a holder for refcounts that automatically decrement../src/block_cache.cpp:1693 }
j->buffer = allocate_buffer("send buffer");
if (j->buffer == 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 + 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);
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_deletion
|| !pe->jobs.empty())
return false;
boost::shared_ptr<piece_manager> s = pe->storage;
| ||
relevance 0 | ../src/bt_peer_connection.cpp:671 | this could be optimized using knuth morris pratt |
this could be optimized using knuth morris pratt../src/bt_peer_connection.cpp:671 {
disconnect(errors::no_memory, op_encryption);
return;
}
#ifdef TORRENT_LOGGING
peer_log(" 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:2212 | if we're finished, send upload_only message |
if we're finished, send upload_only message../src/bt_peer_connection.cpp:2212 if (msg[5 + k / 8] & (0x80 >> (k % 8))) bitfield_string[k] = '1';
else bitfield_string[k] = '0';
}
peer_log("==> BITFIELD [ %s ]", bitfield_string.c_str());
#endif
m_sent_bitfield = true;
send_buffer(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)
{
#ifdef TORRENT_LOGGING
peer_log("==> HAVE [ piece: %d ]", lazy_pieces[i]);
#endif
write_have(lazy_pieces[i]);
}
}
if (m_supports_fast)
send_allowed_set();
}
#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);
}
| ||
relevance 0 | ../src/choker.cpp:332 | 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:332 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:335 | 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:335 }
// ==== 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:340 | make configurable |
make configurable../src/choker.cpp:340 //
// 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 rate = int(p.uploaded_in_last_round()
* 1000 / total_milliseconds(unchoke_interval));
if (rate < rate_threshold) break;
++upload_slots;
| ||
relevance 0 | ../src/choker.cpp:354 | make configurable |
make configurable../src/choker.cpp:354 // 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 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 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/disk_buffer_pool.cpp:329 | perhaps we should sort the buffers here? |
perhaps we should sort the buffers here?../src/disk_buffer_pool.cpp:329 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((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((char*)iov[i].iov_base, l);
check_buffer_level(l);
}
char* disk_buffer_pool::allocate_buffer_impl(mutex::scoped_lock& l, char const* category)
{
TORRENT_ASSERT(m_settings_set);
TORRENT_ASSERT(m_magic == 0x1337);
char* ret;
#if TORRENT_HAVE_MMAP
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
#endif
{
#if defined TORRENT_DISABLE_POOL_ALLOCATOR
| ||
relevance 0 | ../src/disk_io_thread.cpp:879 | 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:879 // 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, tailqueue& completed_jobs
, mutex::scoped_lock& l)
{
DLOG("try_flush_write_blocks: %d\n", num);
list_iterator range = m_disk_cache.write_lru_pieces();
std::vector<std::pair<piece_manager*, int> > pieces;
pieces.reserve(m_disk_cache.num_write_lru_pieces());
| ||
relevance 0 | ../src/disk_io_thread.cpp:922 | 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:922 // this is why we pass in 1 as cont_block to the flushing functions
void disk_io_thread::try_flush_write_blocks(int num, tailqueue& completed_jobs
, mutex::scoped_lock& l)
{
DLOG("try_flush_write_blocks: %d\n", num);
list_iterator range = m_disk_cache.write_lru_pieces();
std::vector<std::pair<piece_manager*, int> > pieces;
pieces.reserve(m_disk_cache.num_write_lru_pieces());
for (list_iterator p = range; p.get() && num > 0; p.next())
{
cached_piece_entry* e = (cached_piece_entry*)p.get();
if (e->num_dirty == 0) continue;
pieces.push_back(std::make_pair(e->storage.get(), int(e->piece)));
}
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);
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;
}
// 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<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);
if (pe == NULL) continue;
if (pe->num_dirty == 0) continue;
| ||
relevance 0 | ../src/disk_io_thread.cpp:1133 | 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:1133 {
INVARIANT_CHECK;
TORRENT_ASSERT(j->next == 0);
TORRENT_ASSERT((j->flags & disk_io_job::in_progress) || !j->storage);
mutex::scoped_lock l(m_cache_mutex);
check_cache_level(l, completed_jobs);
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);
l.unlock();
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]));
ptime start_time = time_now_hires();
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);
if (ret == retry_job)
{
mutex::scoped_lock l(m_job_mutex);
// to avoid busy looping here, give up
// our quanta in case there aren't any other
// jobs to run in between
| ||
relevance 0 | ../src/disk_io_thread.cpp:1161 | 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:1161
ptime start_time = time_now_hires();
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);
if (ret == retry_job)
{
mutex::scoped_lock l(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);
l.unlock();
if (need_sleep) sleep(0);
return;
}
#if TORRENT_USE_ASSERT
| ||
relevance 0 | ../src/disk_io_thread.cpp:1175 | it should clear the hash state even when there's an error, right? |
it should clear the hash state even when there's an error, right?../src/disk_io_thread.cpp:1175 m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, -1);
if (ret == retry_job)
{
mutex::scoped_lock l(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);
l.unlock();
if (need_sleep) sleep(0);
return;
}
#if TORRENT_USE_ASSERT
if (j->action == disk_io_job::hash && !j->error.ec)
{
// a hash job should never return without clearing pe->hash
l.lock();
cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe != NULL)
{
TORRENT_PIECE_ASSERT(pe->hash == NULL, pe);
}
l.unlock();
}
#endif
if (ret == defer_handler) return;
j->ret = ret;
ptime now = time_now_hires();
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 = m_disk_cache.allocate_buffer("send buffer");
if (j->buffer == 0)
{
j->error.ec = error::no_memory;
j->error.operation = storage_error::alloc_cache_piece;
return -1;
}
| ||
relevance 0 | ../src/disk_io_thread.cpp:1870 | maybe the tailqueue_iterator should contain a pointer-pointer instead and have an unlink function |
maybe the tailqueue_iterator should contain a pointer-pointer
instead and have an unlink function../src/disk_io_thread.cpp:1870 j->callback = handler;
add_fence_job(storage, j);
}
void disk_io_thread::async_delete_files(piece_manager* storage
, 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
tailqueue completed_jobs;
// remove outstanding jobs belonging to this torrent
mutex::scoped_lock l2(m_job_mutex);
disk_io_job* qj = (disk_io_job*)m_queued_jobs.get_all();
tailqueue to_abort;
while (qj)
{
disk_io_job* next = (disk_io_job*)qj->next;
#if TORRENT_USE_ASSERTS
qj->next = NULL;
#endif
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);
flush_cache(storage, flush_delete_cache, completed_jobs, l);
l.unlock();
disk_io_job* j = allocate_job(disk_io_job::delete_files);
j->storage = storage->shared_from_this();
j->callback = handler;
add_fence_job(storage, j);
fail_jobs_impl(storage_error(boost::asio::error::operation_aborted), to_abort, completed_jobs);
if (completed_jobs.size())
add_completed_jobs(completed_jobs);
}
| ||
relevance 0 | ../src/disk_io_thread.cpp:2125 | 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:2125 }
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
tailqueue jobs;
bool ok = m_disk_cache.evict_piece(pe, jobs);
TORRENT_PIECE_ASSERT(ok, pe);
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:2386 | 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:2386 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;
file::iovec_t iov;
int ret = 0;
// 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
| ||
relevance 0 | ../src/disk_io_thread.cpp:2456 | 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:2456 for (int i = ph->offset / block_size; i < blocks_in_piece; ++i)
{
iov.iov_len = (std::min)(block_size, piece_size - ph->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(ph->offset == i * block_size, pe);
ph->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 i = 0; i < num_locked_blocks; ++i)
m_disk_cache.dec_block_refcount(pe, locked_blocks[i], 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);
ptime start_time = time_now_hires();
TORRENT_PIECE_ASSERT(ph->offset == i * block_size, pe);
ret = j->storage->get_storage_impl()->readv(&iov, 1, j->piece
, ph->offset, file_flags, j->error);
if (ret < 0)
{
m_disk_cache.free_buffer((char*)iov.iov_base);
l.lock();
break;
}
| ||
relevance 0 | ../src/disk_io_thread.cpp:2698 | 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:2698 {
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);
ptime start_time = time_now_hires();
ret = j->storage->get_storage_impl()->readv(&iov, 1, j->piece
, offset, file_flags, j->error);
if (ret < 0)
{
l.lock();
| ||
relevance 0 | ../src/http_tracker_connection.cpp:185 | support this somehow |
support this somehow../src/http_tracker_connection.cpp:185 url += escape_string(id.c_str(), id.length());
}
#if TORRENT_USE_I2P
if (i2p && tracker_req().i2pconn)
{
url += "&ip=";
url += escape_string(tracker_req().i2pconn->local_endpoint().c_str()
, tracker_req().i2pconn->local_endpoint().size());
url += ".i2p";
}
else
#endif
if (!settings.get_bool(settings_pack::anonymous_mode))
{
std::string announce_ip = settings.get_str(settings_pack::announce_ip);
if (!announce_ip.empty())
{
url += "&ip=" + escape_string(announce_ip.c_str(), announce_ip.size());
}
/* else if (settings.get_bool(settings_pack::announce_double_nat)
&& is_local(m_ses.listen_address()))
{
// only use the global external listen address here
// if it turned out to be on a local network
// since otherwise the tracker should use our
// source IP to determine our origin
url += "&ip=" + print_address(m_ses.listen_address());
}
*/
}
}
m_tracker_connection.reset(new http_connection(get_io_service(), m_man.host_resolver()
, boost::bind(&http_tracker_connection::on_response, shared_from_this(), _1, _2, _3, _4)
, true, settings.get_int(settings_pack::max_http_recv_buffer_size)
, boost::bind(&http_tracker_connection::on_connect, shared_from_this(), _1)
, boost::bind(&http_tracker_connection::on_filter, shared_from_this(), _1, _2)
#ifdef TORRENT_USE_OPENSSL
, tracker_req().ssl_ctx
#endif
));
int timeout = tracker_req().event==tracker_request::stopped
?settings.get_int(settings_pack::stop_tracker_timeout)
:settings.get_int(settings_pack::tracker_completion_timeout);
// when sending stopped requests, prefer the cached DNS entry
// to avoid being blocked for slow or failing responses. Chances
// are that we're shutting down, and this should be a best-effort
// attempt. It's not worth stalling shutdown.
| ||
relevance 0 | ../src/metadata_transfer.cpp:359 | 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:359 std::pair<int, int> offset
= req_to_offset(req, (int)m_tp.metadata().left());
char msg[15];
char* ptr = msg;
#ifdef TORRENT_LOGGING
m_pc.peer_log("==> 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
{
#ifdef TORRENT_LOGGING
m_pc.peer_log("==> DONT HAVE METADATA\n");
#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)
{
if (msg != 14) return false;
if (m_message_index == 0) return false;
if (length > 500 * 1024)
{
| ||
relevance 0 | ../src/packet_buffer.cpp:176 | use compare_less_wrap for this comparison as well |
use compare_less_wrap for this comparison as well../src/packet_buffer.cpp:176 while (new_size < size)
new_size <<= 1;
void** new_storage = (void**)malloc(sizeof(void*) * new_size);
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::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, error_code& ec)
{
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:344 | 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:344 if (block_to_copy == m_piece_size)
{
m_free_slots.push_back(i->second);
m_piece_map.erase(i);
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 = (char*)header.get();
write_uint32(m_max_pieces, ptr);
write_uint32(m_piece_size, ptr);
| ||
relevance 0 | ../src/peer_connection.cpp:1017 | this should be the global download rate |
this should be the global download rate../src/peer_connection.cpp:1017
int rate = 0;
// if we haven't received any data recently, the current download rate
// is not representative
if (time_now() - m_last_piece > seconds(30) && m_download_rate_peak > 0)
{
rate = m_download_rate_peak;
}
else if (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
+ 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:3226 | sort the allowed fast set in priority order |
sort the allowed fast set in priority order../src/peer_connection.cpp:3226
// 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:5870 | 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:5870#if defined TORRENT_LOGGING
peer_log("<<< 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 {
INVARIANT_CHECK;
#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:2040 | 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:2040 , end(m_downloads[piece_pos::piece_downloading].end()); i != end; ++i)
{
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)
{
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)
{
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;
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;
num_blocks = append_blocks(interesting_blocks, backup_blocks2
, num_blocks);
if (num_blocks <= 0) return;
}
if (!suggested_pieces.empty())
{
for (std::vector<int>::const_iterator i = suggested_pieces.begin();
i != suggested_pieces.end(); ++i)
{
// in time critical mode, only pick high priority pieces
| ||
relevance 0 | ../src/piece_picker.cpp:2545 | 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:2545 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(void* 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:512 | 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:512 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);
#if defined TORRENT_LOGGING
session_log("libtorrent configuration: %s\n"
"libtorrent version: %s\n"
"libtorrent revision: %s\n\n"
, TORRENT_CFG_STRING
, LIBTORRENT_VERSION
, LIBTORRENT_REVISION);
#endif // TORRENT_LOGGING
#if TORRENT_USE_RLIMIT
// ---- auto-cap max connections ----
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
{
#if defined TORRENT_LOGGING
session_log(" max number of open files: %d", rl.rlim_cur);
#endif
// deduct some margin for epoll/kqueue, log files,
// futexes, shared objects etc.
rl.rlim_cur -= 20;
// 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)
, int(rl.rlim_cur * 8 / 10)));
// 20% goes towards regular files (see disk_io_thread)
#if defined TORRENT_LOGGING
| ||
relevance 0 | ../src/session_impl.cpp:1727 | instead of having a special case for this, just make the default listen interfaces be "0.0.0.0:6881,[::1]: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,[::1]:6881" and use
the generic path. That would even allow for not listening at all.../src/session_impl.cpp:1727
// reset the retry counter
m_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", true
, m_listen_interface.port()
, m_listen_port_retries, flags, ec);
if (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))
{
int retries = 10;
listen_socket_t s = setup_listener("0.0.0.0", true
, m_settings.get_int(settings_pack::ssl_listen)
, retries, flags | open_ssl_socket, ec);
if (s.sock)
{
TORRENT_ASSERT(!m_abort);
| ||
relevance 0 | ../src/session_impl.cpp:2620 | should this function take a shared_ptr instead? |
should this function take a shared_ptr instead?../src/session_impl.cpp:2620 {
#if defined TORRENT_ASIO_DEBUGGING
complete_async("session_impl::on_socks_accept");
#endif
m_socks_listen_socket.reset();
if (e == asio::error::operation_aborted) return;
if (e)
{
if (m_alerts.should_post<listen_failed_alert>())
m_alerts.post_alert(listen_failed_alert("socks5", listen_failed_alert::accept, e
, listen_failed_alert::socks5));
return;
}
open_new_incoming_socks_connection();
incoming_connection(s);
}
// 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
#if defined TORRENT_LOGGING
session_log(" CLOSING CONNECTION %s : %s"
, print_endpoint(p->remote()).c_str(), ec.message().c_str());
#endif
TORRENT_ASSERT(p->is_disconnecting());
TORRENT_ASSERT(sp.use_count() > 0);
connection_map::iterator i = m_connections.find(sp);
| ||
relevance 0 | ../src/session_impl.cpp:2985 | 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:2985 if (m_auto_manage_time_scaler < 0)
{
INVARIANT_CHECK;
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;
if (m_last_tick - p->connected_time()
> seconds(m_settings.get_int(settings_pack::handshake_timeout)))
p->disconnect(errors::timed_out, peer_connection::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, m_tick_residual / 1000);
// 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:3015 | this should apply to all bandwidth channels |
this should apply to all bandwidth channels../src/session_impl.cpp:3015#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, m_tick_residual / 1000);
// 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.post_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.post_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:3496 | these vectors could be copied from m_torrent_lists, if we would maintain them. That way the first pass over all torrents could be avoided. It would be especially efficient if most torrents are not auto-managed whenever we receive a scrape response (or anything that may change the rank of a torrent) that one torrent could re-sort itself in a list that's kept sorted at all times. That way, this pass over all torrents could be avoided alltogether. |
these vectors could be copied from m_torrent_lists,
if we would maintain them. That way the first pass over
all torrents could be avoided. It would be especially
efficient if most torrents are not auto-managed
whenever we receive a scrape response (or anything
that may change the rank of a torrent) that one torrent
could re-sort itself in a list that's kept sorted at all
times. That way, this pass over all torrents could be
avoided alltogether.../src/session_impl.cpp:3496#if defined TORRENT_LOGGING
if (t->allows_peers())
t->log_to_all_peers("AUTO MANAGER PAUSING TORRENT");
#endif
// use graceful pause for auto-managed torrents
t->set_allow_peers(false, true);
}
}
}
void session_impl::recalculate_auto_managed_torrents()
{
INVARIANT_CHECK;
m_need_auto_manage = false;
if (is_paused()) return;
// these vectors are filled with auto managed torrents
std::vector<torrent*> checking;
std::vector<torrent*> downloaders;
downloaders.reserve(m_torrents.size());
std::vector<torrent*> seeds;
seeds.reserve(m_torrents.size());
// these counters are set to the number of torrents
// of each kind we're allowed to have active
int num_downloaders = settings().get_int(settings_pack::active_downloads);
int num_seeds = settings().get_int(settings_pack::active_seeds);
int checking_limit = 1;
int dht_limit = settings().get_int(settings_pack::active_dht_limit);
int tracker_limit = settings().get_int(settings_pack::active_tracker_limit);
int lsd_limit = settings().get_int(settings_pack::active_lsd_limit);
int hard_limit = settings().get_int(settings_pack::active_limit);
if (num_downloaders == -1)
num_downloaders = (std::numeric_limits<int>::max)();
if (num_seeds == -1)
num_seeds = (std::numeric_limits<int>::max)();
if (hard_limit == -1)
hard_limit = (std::numeric_limits<int>::max)();
if (dht_limit == -1)
dht_limit = (std::numeric_limits<int>::max)();
if (lsd_limit == -1)
lsd_limit = (std::numeric_limits<int>::max)();
if (tracker_limit == -1)
tracker_limit = (std::numeric_limits<int>::max)();
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
| ||
relevance 0 | ../src/session_impl.cpp:3573 | allow extensions to sort torrents for queuing |
allow extensions to sort torrents for queuing../src/session_impl.cpp:3573 if (t->is_finished())
seeds.push_back(t);
else
downloaders.push_back(t);
}
else if (!t->is_paused())
{
if (t->state() == torrent_status::checking_files)
{
if (checking_limit > 0) --checking_limit;
continue;
}
TORRENT_ASSERT(t->m_resume_data_loaded || !t->valid_metadata());
--hard_limit;
}
}
bool handled_by_extension = false;
#ifndef TORRENT_DISABLE_EXTENSIONS
#endif
if (!handled_by_extension)
{
std::sort(checking.begin(), checking.end()
, boost::bind(&torrent::sequence_number, _1) < boost::bind(&torrent::sequence_number, _2));
std::sort(downloaders.begin(), downloaders.end()
, boost::bind(&torrent::sequence_number, _1) < boost::bind(&torrent::sequence_number, _2));
std::sort(seeds.begin(), seeds.end()
, boost::bind(&torrent::seed_rank, _1, boost::ref(m_settings))
> boost::bind(&torrent::seed_rank, _2, boost::ref(m_settings)));
}
auto_manage_torrents(checking, checking_limit, dht_limit, tracker_limit, lsd_limit
, hard_limit, num_downloaders);
if (settings().get_bool(settings_pack::auto_manage_prefer_seeds))
{
auto_manage_torrents(seeds, checking_limit, dht_limit, tracker_limit, lsd_limit
, hard_limit, num_seeds);
auto_manage_torrents(downloaders, checking_limit, dht_limit, tracker_limit, lsd_limit
, hard_limit, num_downloaders);
}
else
{
auto_manage_torrents(downloaders, checking_limit, dht_limit, tracker_limit, lsd_limit
, hard_limit, num_downloaders);
auto_manage_torrents(seeds, checking_limit, dht_limit, tracker_limit, lsd_limit
, hard_limit, num_seeds);
| ||
relevance 0 | ../src/session_impl.cpp:3746 | use a lower limit than m_settings.connections_limit to allocate the to 10% or so of connection slots for incoming connections |
use a lower limit than m_settings.connections_limit
to allocate the to 10% or so of connection slots for incoming
connections../src/session_impl.cpp:3746 // 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 limit = m_settings.get_int(settings_pack::connections_limit)
- num_connections();
// 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:3889 | 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:3889 torrent* t = p->associated_torrent().lock().get();
torrent_peer* pi = p->peer_info_struct();
if (p->ignore_unchoke_slots() || t == 0 || pi == 0
|| pi->web_seed || t->is_paused())
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()) 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);
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.post_alert(performance_alert(torrent_handle()
, performance_alert::bittyrant_with_no_uplimit));
}
int 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);
int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, allowed_upload_slots / 5);
| ||
relevance 0 | ../src/session_impl.cpp:3936 | this should be called for all peers! |
this should be called for all peers!../src/session_impl.cpp:3936 , unchoke_interval, m_settings);
m_stats_counters.set_value(counters::num_unchoke_slots
, allowed_upload_slots);
int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, allowed_upload_slots / 5);
// reserve some upload slots for optimistic unchokes
int unchoke_set_size = allowed_upload_slots;
// go through all the peers and unchoke the first ones and choke
// all the other ones.
for (std::vector<peer_connection*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_connection* p = *i;
TORRENT_ASSERT(p);
TORRENT_ASSERT(!p->ignore_unchoke_slots());
// this will update the m_uploaded_at_last_unchoke
p->reset_choke_counters();
torrent* t = p->associated_torrent().lock().get();
TORRENT_ASSERT(t);
if (unchoke_set_size > 0)
{
// yes, this peer should be unchoked
if (p->is_choked())
{
if (!t->unchoke_peer(*p))
continue;
}
--unchoke_set_size;
TORRENT_ASSERT(p->peer_info_struct());
if (p->peer_info_struct()->optimistically_unchoked)
{
// force a new optimistic unchoke
// since this one just got promoted into the
// proper unchoke set
m_optimistic_unchoke_time_scaler = 0;
p->peer_info_struct()->optimistically_unchoked = false;
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
}
}
else
{
// no, this peer should be choked
TORRENT_ASSERT(p->peer_info_struct());
| ||
relevance 0 | ../src/session_impl.cpp:4327 | 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 |
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../src/session_impl.cpp:4327 t->status(&*i, flags);
}
}
void session_impl::post_torrent_updates(boost::uint32_t flags)
{
INVARIANT_CHECK;
TORRENT_ASSERT(is_single_thread());
std::auto_ptr<state_update_alert> alert(new state_update_alert());
std::vector<torrent*>& state_updates
= m_torrent_lists[aux::session_impl::torrent_state_updates];
alert->status.reserve(state_updates.size());
#if TORRENT_USE_ASSERTS
m_posting_torrent_updates = true;
#endif
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());
alert->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(&alert->status.back(), flags);
t->clear_in_state_update();
}
state_updates.clear();
#if TORRENT_USE_ASSERTS
m_posting_torrent_updates = false;
#endif
m_alerts.post_alert_ptr(alert.release());
}
void session_impl::post_session_stats()
{
std::auto_ptr<session_stats_alert> alert(new session_stats_alert());
std::vector<boost::uint64_t>& values = alert->values;
values.resize(counters::num_counters, 0);
m_disk_thread.update_stats_counters(m_stats_counters);
m_stats_counters.set_value(counters::sent_ip_overhead_bytes
| ||
relevance 0 | ../src/storage.cpp:716 | 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:716 for (;;)
{
if (file_offset < files().file_size(file_index))
break;
file_offset -= files().file_size(file_index);
++file_index;
TORRENT_ASSERT(file_index != files().num_files());
}
error_code ec;
file_handle handle = open_file_impl(file_index, file::read_only, ec);
if (ec) return slot;
boost::int64_t data_start = handle->sparse_end(file_offset);
return int((data_start + files().piece_length() - 1) / files().piece_length());
}
bool default_storage::verify_resume_data(lazy_entry const& rd, storage_error& ec)
{
lazy_entry const* 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);
}
}
lazy_entry const* 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));
}
lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
if (file_sizes_ent == 0)
{
ec.ec = errors::missing_file_sizes;
return false;
}
if (file_sizes_ent->list_size() == 0)
{
ec.ec = errors::no_files_in_resume_data;
| ||
relevance 0 | ../src/storage.cpp:1012 | if everything moves OK, except for the partfile we currently won't update the save path, which breaks things. it would probably make more sense to give up on the partfile |
if everything moves OK, except for the partfile
we currently won't update the save path, which breaks things.
it would probably make more sense to give up on the partfile../src/storage.cpp:1012 if (ec)
{
ec.file = i->second;
ec.operation = storage_error::copy;
}
else
{
// ignore errors when removing
error_code e;
remove_all(old_path, e);
}
break;
}
}
}
if (!ec)
{
if (m_part_file)
{
m_part_file->move_partfile(save_path, ec.ec);
if (ec)
{
ec.file = -1;
ec.operation = storage_error::partfile_move;
return piece_manager::fatal_disk_error;
}
}
m_save_path = save_path;
}
return ret;
}
int default_storage::readv(file::iovec_t const* bufs, int num_bufs
, int slot, int offset, int flags, storage_error& ec)
{
fileop op = { &file::readv
, file::read_only | flags };
#ifdef TORRENT_SIMULATE_SLOW_READ
boost::thread::sleep(boost::get_system_time()
+ boost::posix_time::milliseconds(1000));
#endif
return readwritev(bufs, slot, offset, num_bufs, op, ec);
}
int default_storage::writev(file::iovec_t const* bufs, int num_bufs
, int slot, int offset, int flags, storage_error& ec)
{
fileop op = { &file::writev
, file::read_write | flags };
| ||
relevance 0 | ../src/torrent.cpp:508 | 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:508
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(error_code(errors::duplicate_torrent, get_libtorrent_category()), 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, serge 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:659 | 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:659 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(error_code(errors::duplicate_torrent, get_libtorrent_category()), 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);
#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);
m_ses.add_obfuscated_hash(h.final(), shared_from_this());
#endif
| ||
relevance 0 | ../src/torrent.cpp:1461 | 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:1461 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));
#if defined TORRENT_LOGGING
std::string names;
bool match = false;
#endif
for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
{
GENERAL_NAME* gen = sk_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;
#if defined TORRENT_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)
{
#if defined TORRENT_LOGGING
match = true;
| ||
relevance 0 | ../src/torrent.cpp:1865 | 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:1865 {
m_have_all = true;
m_ses.get_io_service().post(boost::bind(&torrent::files_checked, shared_from_this()));
m_resume_data.reset();
update_gauge();
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)) ++num_pad_files;
if (!fs.pad_file_at(i) || fs.file_size(i) == 0) continue;
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 (int(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:2061 | 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:2061 // 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)
{
if ((*i)->type() != peer_connection::bittorrent_connection) continue;
bt_peer_connection* p = (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 (bt_peer_connection*)p;
}
#endif
| ||
relevance 0 | ../src/torrent.cpp:2736 | 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:2736 // 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
, m_ses.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())
{
#if defined TORRENT_LOGGING
debug_log("DHT: no dht initialized");
#endif
return;
}
if (!should_announce_dht())
{
#if defined TORRENT_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:3515 | add one peer per IP the hostname resolves to |
add one peer per IP the hostname resolves to../src/torrent.cpp:3515#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
#if defined TORRENT_LOGGING
if (e)
debug_log("peer name lookup error: %s", e.message().c_str());
#endif
if (e || host_list.empty() || m_ses.is_aborted()) return;
tcp::endpoint host(host_list.front(), port);
if (m_apply_ip_filter
&& m_ses.get_ip_filter().access(host.address()) & ip_filter::blocked)
{
#if defined TORRENT_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().post_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
{
| ||
relevance 0 | ../src/torrent.cpp:4509 | update suggest_piece? |
update suggest_piece?../src/torrent.cpp:4509
void torrent::peer_has_all(peer_connection const* peer)
{
if (has_picker())
{
m_picker->inc_refcount_all(peer);
}
#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())
{
m_picker->dec_refcount(bits, peer);
}
#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())
{
m_picker->dec_refcount(index, peer);
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:4652 | 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:4652 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 i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* peer = *i;
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)
(*p)->send_suggest(i->piece_index);
}
}
void torrent::abort()
| ||
relevance 0 | ../src/torrent.cpp:6625 | 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:6625 m_last_upload = tmp == -1 ? (std::numeric_limits<boost::int16_t>::min)() : now - tmp;
if (m_use_resume_save_path)
{
std::string p = rd.dict_find_string_value("save_path");
if (!p.empty()) m_save_path = p;
}
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);
}
lazy_entry const* 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_seed_mode && !m_override_resume_data)
{
lazy_entry const* file_priority = rd.dict_find_list("file_priority");
if (file_priority && file_priority->list_size()
== m_torrent_file->num_files())
{
int num_files = m_torrent_file->num_files();
m_file_priority.resize(num_files);
for (int i = 0; i < num_files; ++i)
m_file_priority[i] = file_priority->list_int_value_at(i, 1);
// unallocated slots are assumed to be priority 1, so cut off any
// trailing ones
int end_range = num_files - 1;
for (; end_range >= 0; --end_range) if (m_file_priority[end_range] != 1) break;
m_file_priority.resize(end_range + 1);
| ||
relevance 0 | ../src/torrent.cpp:6743 | 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:6743 add_web_seed(url, web_seed_entry::http_seed);
}
}
if (m_torrent_file->is_merkle_torrent())
{
lazy_entry const* 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;
}
boost::shared_ptr<const torrent_info> torrent::get_torrent_copy()
{
if (!m_torrent_file->is_valid()) return boost::shared_ptr<const torrent_info>();
if (!need_loaded()) return boost::shared_ptr<const torrent_info>();
return m_torrent_file;
}
void torrent::write_resume_data(entry& ret) const
{
using namespace libtorrent::detail; // for write_*_endpoint()
ret["file-format"] = "libtorrent resume file";
ret["file-version"] = 1;
ret["libtorrent-version"] = LIBTORRENT_VERSION;
ret["total_uploaded"] = m_total_uploaded;
ret["total_downloaded"] = m_total_downloaded;
ret["active_time"] = active_time();
ret["finished_time"] = finished_time();
ret["seeding_time"] = seeding_time();
| ||
relevance 0 | ../src/torrent.cpp:6934 | 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:6934 pieces.resize(m_torrent_file->num_pieces());
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:8936 | 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:8936 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().post_alert(save_resume_data_failed_alert(get_handle()
, errors::no_metadata));
return;
}
if (!m_storage.get())
{
alerts().post_alert(save_resume_data_failed_alert(get_handle()
, errors::destructing_torrent));
return;
}
if ((flags & torrent_handle::only_if_modified) && !m_need_save_resume_data)
{
alerts().post_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();
| ||
relevance 0 | ../src/torrent.cpp:10546 | 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:10546 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->type != type) continue;
ret.insert(i->url);
}
return ret;
| ||
relevance 0 | ../src/torrent_peer.cpp:176 | how do we deal with our external address changing? |
how do we deal with our external address changing?../src/torrent_peer.cpp:176 , 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;
}
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;
}
}
boost::uint64_t torrent_peer::total_upload() const
{
if (connection != 0)
{
TORRENT_ASSERT(prev_amount_upload == 0);
return connection->statistics().total_payload_upload();
}
else
{
return boost::uint64_t(prev_amount_upload) << 10;
}
| ||
relevance 0 | ../src/udp_socket.cpp:286 | 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:286 --m_v6_outstanding;
}
else
#endif
{
TORRENT_ASSERT(m_v4_outstanding > 0);
--m_v4_outstanding;
}
if (ec == asio::error::operation_aborted) return;
if (m_abort) return;
CHECK_MAGIC;
for (;;)
{
error_code ec;
udp::endpoint ep;
size_t bytes_transferred = s->receive_from(asio::buffer(m_buf, m_buf_size), ep, 0, ec);
#ifdef TORRENT_WINDOWS
if ((ec == error_code(ERROR_MORE_DATA, system_category())
|| ec == 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 (ec == asio::error::would_block || ec == asio::error::try_again) break;
on_read_impl(s, ep, ec, bytes_transferred);
}
call_drained_handler();
setup_read(s);
}
void udp_socket::call_handler(error_code const& ec, udp::endpoint const& ep, char const* buf, int size)
{
m_observers_locked = true;
for (std::vector<udp_socket_observer*>::iterator i = m_observers.begin();
i != m_observers.end();)
{
bool ret = false;
TORRENT_TRY {
ret = (*i)->incoming_packet(ec, ep, buf, size);
} TORRENT_CATCH (std::exception&) {}
if (*i == NULL) i = m_observers.erase(i);
| ||
relevance 0 | ../src/udp_socket.cpp:777 | use the system resolver_interface here |
use the system resolver_interface here../src/udp_socket.cpp:777
void udp_socket::set_proxy_settings(proxy_settings const& ps)
{
CHECK_MAGIC;
TORRENT_ASSERT(is_single_thread());
error_code ec;
m_socks5_sock.close(ec);
m_tunnel_packets = false;
m_proxy_settings = ps;
if (m_abort) 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::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
{
#if defined TORRENT_ASIO_DEBUGGING
complete_async("udp_socket::on_name_lookup");
#endif
#if TORRENT_USE_ASSERTS
TORRENT_ASSERT(m_outstanding_resolve > 0);
--m_outstanding_resolve;
#endif
TORRENT_ASSERT(m_outstanding_ops > 0);
--m_outstanding_ops;
TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect
+ m_outstanding_timeout
+ m_outstanding_resolve
+ m_outstanding_socks);
if (m_abort) return;
| ||
relevance 0 | ../src/upnp.cpp:71 | listen_interface is not used. It's meant to bind the broadcast socket |
listen_interface is not used. It's meant to bind the broadcast socket../src/upnp.cpp:71#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <cstdlib>
namespace libtorrent {
namespace upnp_errors
{
boost::system::error_code make_error_code(error_code_enum e)
{
return error_code(e, get_upnp_category());
}
} // upnp_errors namespace
static error_code ec;
upnp::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)
: 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", ec), 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);
}
void upnp::start(void* state)
{
error_code ec;
m_socket.open(boost::bind(&upnp::on_reply, self(), _1, _2, _3)
, m_refresh_timer.get_io_service(), ec);
if (state)
{
upnp_state_t* s = (upnp_state_t*)state;
| ||
relevance 0 | ../src/ut_metadata.cpp:316 | 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:316 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)
{
if (extended_msg != 2) return false;
if (m_message_index == 0) return false;
if (length > 17 * 1024)
{
#ifdef TORRENT_LOGGING
m_pc.peer_log("<== UT_METADATA [ packet too big %d ]", length);
#endif
m_pc.disconnect(errors::invalid_metadata_message, peer_connection_interface::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)
{
#ifdef TORRENT_LOGGING
m_pc.peer_log("<== UT_METADATA [ not a dictionary ]");
#endif
| ||
relevance 0 | ../src/utp_stream.cpp:1644 | this loop may not be very efficient |
this loop may not be very efficient../src/utp_stream.cpp:1644
char* m_buf;
};
// 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 flags)
{
INVARIANT_CHECK;
bool 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 = (packet*)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:73 | 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:73{
web_connection_base::web_connection_base(
peer_connection_args const& pack
, web_seed_t& web)
: 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;
// 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_tracker.cpp:295 | ideally this function would be called when the put completes |
ideally this function would be called when the
put completes../src/kademlia/dht_tracker.cpp:295 // since it controls whether we re-put the content
TORRENT_ASSERT(!it.is_mutable());
f(it);
return false;
}
bool get_mutable_item_callback(item& it, boost::function<void(item const&)> f)
{
// the reason to wrap here is to control the return value
// since it controls whether we re-put the content
TORRENT_ASSERT(it.is_mutable());
f(it);
return false;
}
bool put_immutable_item_callback(item& it, boost::function<void()> f
, entry data)
{
TORRENT_ASSERT(!it.is_mutable());
it.assign(data);
f();
return true;
}
bool put_mutable_item_callback(item& it, boost::function<void(item&)> cb)
{
cb(it);
return true;
}
void dht_tracker::get_item(sha1_hash const& target
, boost::function<void(item const&)> cb)
{
m_dht.get_item(target, boost::bind(&get_immutable_item_callback, _1, cb));
}
// key is a 32-byte binary string, the public key to look up.
// the salt is optional
void dht_tracker::get_item(char const* key
, boost::function<void(item const&)> cb
, std::string salt)
{
m_dht.get_item(key, salt, boost::bind(&get_mutable_item_callback, _1, cb));
}
void dht_tracker::put_item(entry data
, boost::function<void()> cb)
{
std::string flat_data;
bencode(std::back_inserter(flat_data), data);
sha1_hash target = item_target_id(
| ||
relevance 0 | ../include/libtorrent/bitfield.hpp:158 | rename to data() ? |
rename to data() ?../include/libtorrent/bitfield.hpp:158 if (m_buf[i] != 0) return false;
}
return true;
}
// returns the size of the bitfield in bits.
int size() const
{
return m_buf == NULL ? 0 : m_buf[-1];
}
int num_words() const
{
return (size() + 31) / 32;
}
// returns true if the bitfield has zero size.
bool empty() const { return m_buf == NULL ? true : m_buf[-1] == 0; }
// returns a pointer to the internal buffer of the bitfield.
char const* bytes() const { return (char const*)m_buf; }
// copy operator
bitfield& operator=(bitfield const& rhs)
{
assign(rhs.bytes(), rhs.size());
return *this;
}
// count the number of bits in the bitfield that are set to 1.
int count() const
{
int ret = 0;
const int words = num_words();
#if TORRENT_HAS_SSE
unsigned int cpui[4];
cpuid(cpui, 1);
if (cpui[2] & (1 << 23))
{
for (int i = 0; i < words; ++i)
{
#ifdef __GNUC__
ret += __builtin_popcount(m_buf[i]);
#else
ret += _mm_popcnt_u32(m_buf[i]);
#endif
}
return ret;
}
#endif // TORRENT_HAS_SSE
| ||
relevance 0 | ../include/libtorrent/block_cache.hpp:213 | 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:213
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 calulcating 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
ptime 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
boost::uint32_t marked_for_deletion:1;
// this is set to true once we flush blocks past
// the hash cursor. Once this happens, there's
| ||
relevance 0 | ../include/libtorrent/config.hpp:334 | Make this count Unicode characters instead of bytes on windows |
Make this count Unicode characters instead of bytes on windows../include/libtorrent/config.hpp:334#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
// posix
#elif defined NAME_MAX
#define TORRENT_MAX_PATH NAME_MAX
// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows
#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
| ||
relevance 0 | ../include/libtorrent/disk_buffer_pool.hpp:134 | try to remove the observers, only using the async_allocate handlers |
try to remove the observers, only using the async_allocate handlers../include/libtorrent/disk_buffer_pool.hpp:134
// number of bytes per block. The BitTorrent
// protocol defines the block size to 16 KiB.
const int m_block_size;
// number of disk buffers currently allocated
int m_in_use;
// cache size limit
int m_max_use;
// if we have exceeded the limit, we won't start
// allowing allocations again until we drop below
// this low watermark
int m_low_watermark;
// if we exceed the max number of buffers, we start
// adding up callbacks to this queue. Once the number
// of buffers in use drops below the low watermark,
// we start calling these functions back
std::vector<boost::shared_ptr<disk_observer> > m_observers;
// these handlers are executed when a new buffer is available
std::vector<handler_t> m_handlers;
// callback used to tell the cache it needs to free up some blocks
boost::function<void()> m_trigger_cache_trim;
// set to true to throttle more allocations
bool m_exceeded_max_size;
// this is the main thread io_service. Callbacks are
// posted on this in order to have them execute in
// the main thread.
io_service& m_ios;
private:
void check_buffer_level(mutex::scoped_lock& l);
mutable mutex m_pool_mutex;
int m_cache_buffer_chunk_size;
bool m_lock_disk_cache;
#if TORRENT_HAVE_MMAP
// the file descriptor of the cache mmap file
int m_cache_fd;
// the pointer to the block of virtual address space
// making up the mmapped cache space
char* m_cache_pool;
| ||
relevance 0 | ../include/libtorrent/file.hpp:168 | move this into a separate header file, TU pair |
move this into a separate header file, TU pair../include/libtorrent/file.hpp:168 TORRENT_EXTRA_EXPORT bool is_root_path(std::string const& f);
// internal used by create_torrent.hpp
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);
// 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/peer_connection.hpp:205 | 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:205 , 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:1055 | 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:1055
// 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:45 | make this interface smaller! |
make this interface smaller!../include/libtorrent/peer_connection_interface.hpp:45SUBSTITUTE 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_PEER_CONNECTION_INTERFACE_HPP
#define TORRENT_PEER_CONNECTION_INTERFACE_HPP
#include "libtorrent/socket.hpp"
#include "libtorrent/error_code.hpp"
namespace libtorrent
{
struct torrent_peer;
class stat;
struct peer_info;
struct peer_connection_interface
{
// these constants are used to identify the operation
// that failed, causing a peer to disconnect
enum operation_t
{
// this is used when the bittorrent logic
// determines to disconnect
op_bittorrent = 0,
op_iocontrol,
op_getpeername,
op_getname,
op_alloc_recvbuf,
op_alloc_sndbuf,
op_file_write,
op_file_read,
op_file,
op_sock_write,
op_sock_read,
op_sock_open,
op_sock_bind,
op_available,
op_encryption,
op_connect,
op_ssl_handshake,
op_get_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;
| ||
relevance 0 | ../include/libtorrent/performance_counters.hpp:132 | 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:132 // 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:442 | 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:442 | ||
relevance 0 | ../include/libtorrent/performance_counters.hpp:443 | 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:443 num_utp_deleted,
num_counters,
num_gauge_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
mutex m_mutex;
boost::int64_t m_stats_counter[num_counters];
#endif
};
}
#endif
| ||
relevance 0 | ../include/libtorrent/piece_picker.hpp:761 | should this be allocated lazily? |
should this be allocated lazily?../include/libtorrent/piece_picker.hpp:761
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 wich 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:171 | 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:171 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:255 | 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:255
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:
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.hpp:861 | add get_peer_class_type_filter() as well |
add get_peer_class_type_filter() as well../include/libtorrent/session.hpp:861 //
// 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:1099 | 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:1099 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_sparse_regions`` is a limit of the number of *sparse regions*
// in a torrent. A sparse region is defined as a hole of pieces we
// have not yet downloaded, in between pieces that have been
// downloaded. This is used as a hack for windows vista which has a
// bug where you cannot write files with more than a certain number of
// sparse regions. This limit is not hard, it will be exceeded. Once
// it's exceeded, pieces that will maintain or decrease the number of
// sparse regions are prioritized. To disable this functionality, set
// this to 0. It defaults to 0 on all platforms except windows.
max_sparse_regions,
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,
// ``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,
// ``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
// boundry.
//
// When a piece in the write cache has ``write_cache_line_size``
// contiguous blocks in it, they will be flushed. Setting this to 1
// effectively disables the write cache.
read_cache_line_size,
write_cache_line_size,
| ||
relevance 0 | ../include/libtorrent/torrent.hpp:1265 | this wastes 5 bits per file |
this wastes 5 bits per file../include/libtorrent/torrent.hpp:1265 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 vector contains the number of bytes completely
// downloaded (as in passed-hash-check) in each file.
// this lets us trigger on individual files completing
// the vector is allocated lazily, when file progress
// is first queried by the client
std::vector<boost::uint64_t> 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;
std::string m_username;
std::string m_password;
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.
| ||
relevance 0 | ../include/libtorrent/torrent.hpp:1324 | These two bitfields should probably be coalesced into one |
These two bitfields should probably be coalesced into one../include/libtorrent/torrent.hpp:1324 // 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:123 | 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/torrent_info.hpp:123
// 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
ptime next_announce;
// no announces before this time
ptime 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/torrent_info.hpp:270 | 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:270 // 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 lazy_entry will create a torrent_info
// object from the information found in the given torrent_file. The
// lazy_entry represents a tree node in an bencoded file. To load an
// ordinary .torrent file into a lazy_entry, use lazy_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:382 | this should be unique_ptr in the future |
this should be unique_ptr in the future../include/libtorrent/tracker_manager.hpp:382 // 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);
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; }
struct ip_filter const& ip_filter() const { return m_ip_filter; }
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;
struct ip_filter const& m_ip_filter;
class udp_socket& m_udp_socket;
resolver_interface& m_host_resolver;
aux::session_settings const& m_settings;
counters& m_stats_counters;
#if defined TORRENT_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:108 | support using the windows API for UPnP operations as well |
support using the windows API for UPnP operations as well../include/libtorrent/upnp.hpp:108 external_port_must_be_wildcard = 727
};
// hidden
TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);
}
// the boost.system error category for UPnP errors
TORRENT_EXPORT boost::system::error_category& get_upnp_category();
// int: port-mapping index
// address: external address as queried from router
// int: external port
// std::string: error message
// an empty string as error means success
// a port-mapping index of -1 means it's
// an informational log message
typedef boost::function<void(int, address, int, error_code const&)> portmap_callback_t;
typedef boost::function<void(char const*)> log_callback_t;
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 start(void* state = 0);
void* drain_state();
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:395 | 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:395 for (typename Mutable_Buffers::const_iterator i = buffers.begin()
, end(buffers.end()); i != end; ++i)
{
using asio::buffer_cast;
using 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, asio::error::not_connected, 0));
| ||
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:836 | should this be renamed m_outgoing_interfaces? |
should this be renamed m_outgoing_interfaces?../include/libtorrent/aux_/session_impl.hpp:836 // listen socket. For each retry the port number
// is incremented by one
int m_listen_port_retries;
// 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 fasion
// each element is a device name or IP address (in string form) and
// a port number. The port determins 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
boost::asio::ssl::context* ssl_ctx() { 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
// when as a socks proxy is used for peers, also
// listen for incoming connections on a socks connection
boost::shared_ptr<socket_type> m_socks_listen_socket;
boost::uint16_t m_socks_listen_port;
// round-robin index into m_net_interfaces
mutable boost::uint8_t m_interface_index;
| ||
relevance 0 | ../include/libtorrent/aux_/session_impl.hpp:887 | replace this by a proper asio timer |
replace this by a proper asio timer../include/libtorrent/aux_/session_impl.hpp:887
void open_new_incoming_socks_connection();
enum listen_on_flags_t
{
open_ssl_socket = 0x10
};
listen_socket_t setup_listener(std::string const& device
, bool ipv4, int port, int& retries, 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:892 | replace this by a proper asio timer |
replace this by a proper asio timer../include/libtorrent/aux_/session_impl.hpp:892 {
open_ssl_socket = 0x10
};
listen_socket_t setup_listener(std::string const& device
, bool ipv4, int port, int& retries, 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 decresed 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:899 | replace this by a proper asio timer |
replace this by a proper asio timer../include/libtorrent/aux_/session_impl.hpp:899
#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 decresed 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;
// 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;
// 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;
// statistics gathered from all torrents.
| ||
relevance 0 | ../include/libtorrent/aux_/session_interface.hpp:229 | 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:229
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;
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(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
| ||