there are still some serious issues with storage when having large torrents (about 700 meg and up at least)

This commit is contained in:
Arvid Norberg 2003-12-01 05:01:40 +00:00
parent 0019e23b4f
commit f21d6a0f7f
18 changed files with 458 additions and 174 deletions

View File

@ -182,8 +182,9 @@ int main(int argc, char* argv[])
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
// t.convert_file_names();
t.print(std::cout);
handles.push_back(s.add_torrent(t, ""));
handles.push_back(s.add_torrent(t, boost::filesystem::path("", boost::filesystem::native)));
}
catch (std::exception& e)
{

View File

@ -137,7 +137,7 @@ namespace libtorrent
void cancel_block(piece_block block);
bool is_interesting() const throw() { return m_interesting; }
bool has_choked() const throw() { return m_choked; }
bool is_choked() const throw() { return m_choked; }
bool is_peer_interested() const throw() { return m_peer_interested; }
bool has_peer_choked() const throw() { return m_peer_choked; }
@ -146,7 +146,7 @@ namespace libtorrent
// may be zero if the connection is an incoming connection
// and it hasn't received enough information to determine
// which torrent it should be associated with
torrent* associated_torrent() const throw() { return m_torrent; }
torrent* associated_torrent() const throw() { return m_attached_to_torrent?m_torrent:0; }
const stat& statistics() const { return m_statistics; }
@ -239,7 +239,20 @@ namespace libtorrent
selector& m_selector;
boost::shared_ptr<libtorrent::socket> m_socket;
// this is the torrent this connection is
// associated with. If the connection is an
// incoming conncetion, this is set to zero
// until the info_hash is received. Then it's
// set to the torrent it belongs to.
torrent* m_torrent;
// this is set to false until the peer_id
// is received from the other end. Or is
// true if the conenction was actively
// opened from our side.
bool m_attached_to_torrent;
detail::session_impl* m_ses;
// is true if it was we that connected to the peer
// and false if we got an incomming connection

View File

@ -36,6 +36,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
#include <vector>
#include <boost/weak_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "libtorrent/peer.hpp"
#include "libtorrent/piece_picker.hpp"
@ -53,9 +56,13 @@ namespace libtorrent
public:
policy(torrent* t);
// this is called each time we get an incoming connection
// return true to accept the connection
bool accept_connection(const address& remote);
// this is called every 10 seconds to allow
// for peer choking management
void pulse();
// called when an incoming connection is accepted
void new_connection(const boost::weak_ptr<peer_connection>& c);
// this is called once for every peer we get from
// the tracker
@ -83,8 +90,77 @@ namespace libtorrent
// the peer is not interested in our pieces
void not_interested(peer_connection& c);
#ifndef NDEBUG
bool has_connection(const peer_connection* p);
#endif
private:
struct peer
{
peer(const peer_id& pid)
: id(pid)
, last_optimistically_unchoked(boost::posix_time::second_clock::local_time())
, connected(boost::posix_time::second_clock::local_time())
, optimistic_unchokes(0)
, prev_amount_upload(0)
, prev_amount_download(0)
{}
bool operator==(const peer_id& pid) const
{ return id == pid; }
// the id of the peer. This is needed to store information
// about peers that aren't connected right now. This
// is to avoid peers reconnecting. unconnected entries
// will be saved a limited amount of time
peer_id id;
// the time when this peer was optimistically unchoked
// the last time.
boost::posix_time::ptime last_optimistically_unchoked;
// the time when the peer connected to us
// or disconnected if it isn't connected right now
boost::posix_time::ptime connected;
// the number of optimistic unchokes this peer has
// been given
int optimistic_unchokes;
// this is the accumulated amount of
// uploaded and downloaded data to this
// peer. It only accounts for what was
// shared during the last connection to
// this peer. i.e. These are only updated
// when the connection is closed. For the
// total amount of upload and download
// we'll have to add thes figures with the
// statistics from the peer_connection.
int prev_amount_upload;
int prev_amount_download;
// if the peer is connected now, this
// will refer to a valid peer_connection
boost::weak_ptr<peer_connection> connection;
};
// a functor that identifies peers that have disconnected and that
// are too old for still being saved.
struct old_disconnected_peer
{
bool operator()(const peer& p)
{
using namespace boost::posix_time;
return p.connection.expired()
&& second_clock::local_time() - p.connected > seconds(5*60);
}
};
std::vector<peer> m_peers;
int m_num_peers;
torrent* m_torrent;

View File

@ -171,6 +171,7 @@ namespace libtorrent
alert_manager m_alerts;
#ifndef NDEBUG
void assert_invariant();
boost::shared_ptr<logger> create_log(std::string name);
boost::shared_ptr<logger> m_logger;
#endif

View File

@ -33,6 +33,9 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_SOCKET_WIN_HPP_INCLUDED
#define TORRENT_SOCKET_WIN_HPP_INCLUDED
// TODO: remove the dependency of
// platform specific headers here.
#if defined(_WIN32)
#include <winsock2.h>
#else
@ -135,57 +138,32 @@ namespace libtorrent
enum error_code
{
#if defined(_WIN32)
netdown = WSAENETDOWN,
fault = WSAEFAULT,
access = WSAEACCES,
address_in_use = WSAEADDRINUSE,
address_not_available = WSAEADDRNOTAVAIL,
in_progress = WSAEINPROGRESS,
interrupted = WSAEINTR,
invalid = WSAEINVAL,
net_reset = WSAENETRESET,
not_connected = WSAENOTCONN,
no_buffers = WSAENOBUFS,
operation_not_supported = WSAEOPNOTSUPP,
not_socket = WSAENOTSOCK,
shutdown = WSAESHUTDOWN,
would_block = WSAEWOULDBLOCK,
connection_reset = WSAECONNRESET,
timed_out = WSAETIMEDOUT,
connection_aborted = WSAECONNABORTED,
message_size = WSAEMSGSIZE,
not_ready = WSAEALREADY,
no_support = WSAEAFNOSUPPORT,
connection_refused = WSAECONNREFUSED,
is_connected = WSAEISCONN,
net_unreachable = WSAENETUNREACH
#else
netdown = ENETDOWN,
fault = EFAULT,
access = EACCES,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
in_progress = EINPROGRESS,
interrupted = EINTR,
invalid = EINVAL,
net_reset = ENETRESET,
not_connected = ENOTCONN,
no_buffers = ENOMEM,
operation_not_supported = EOPNOTSUPP,
not_socket = ENOTSOCK,
shutdown = ESHUTDOWN,
would_block = EAGAIN,
connection_reset = ECONNRESET,
timed_out = ETIMEDOUT,
connection_aborted = ECONNABORTED,
message_size = EMSGSIZE,
not_ready = EALREADY,
no_support = EAFNOSUPPORT,
connection_refused = ECONNREFUSED,
is_connected = EISCONN,
net_unreachable = ENETUNREACH
#endif
netdown,
fault,
access,
address_in_use,
address_not_available,
in_progress,
interrupted,
invalid,
net_reset,
not_connected,
no_buffers,
operation_not_supported,
not_socket,
shutdown,
would_block,
connection_reset,
timed_out,
connection_aborted,
message_size,
not_ready,
no_support,
connection_refused,
is_connected,
net_unreachable,
not_initialized,
unknown_error
};
error_code last_error() const;

View File

@ -58,6 +58,10 @@ namespace libtorrent
std::fill(m_upload_per_second_history, m_upload_per_second_history+history, 0);
}
// TODO: these function should take two arguments
// to be able to count both total data sent and also
// count only the actual payload (not counting the
// protocol chatter)
void received_bytes(int num_bytes)
{ m_downloaded += num_bytes; m_total_download += num_bytes; }
void sent_bytes(int num_bytes)

View File

@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/limits.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
#include "libtorrent/entry.hpp"
@ -115,7 +116,7 @@ namespace libtorrent
void reopen();
// the file itself
std::fstream m_file;
boost::filesystem::fstream m_file;
// the mode with which this file was opened
open_mode m_mode;

View File

@ -87,6 +87,9 @@ namespace libtorrent
void abort() { m_abort = true; m_event = event_stopped; }
bool is_aborted() const { return m_abort; }
// is called every second by session.
void second_tick();
// returns true if it time for this torrent to make another
// tracker request
bool should_request() const throw()
@ -96,9 +99,6 @@ namespace libtorrent
return m_next_request < boost::posix_time::second_clock::local_time();
}
bool failed() const throw() { return !m_failed.empty(); }
const char* fail_reason() const throw() { return m_failed.c_str(); }
void print(std::ostream& os) const;
void allocate_files(detail::piece_checker_data* data,
@ -114,9 +114,12 @@ namespace libtorrent
torrent_status status() const;
void connect_to_peer(const address& a, const peer_id& id);
boost::weak_ptr<peer_connection> connect_to_peer(
const address& a
, const peer_id& id);
const torrent_info& torrent_file() const throw() { return m_torrent_file; }
const torrent_info& torrent_file() const throw()
{ return m_torrent_file; }
policy& get_policy() { return *m_policy; }
storage* filesystem() { return &m_storage; }
@ -128,11 +131,7 @@ namespace libtorrent
// used by peer_connection to attach itself to a torrent
// since incoming connections don't know what torrent
// they're a part of until they have received an info_hash.
void attach_peer(peer_connection* p)
{
assert(std::find(m_connections.begin(), m_connections.end(), p) == m_connections.end());
m_connections.push_back(p);
}
void attach_peer(peer_connection* p);
// this will remove the peer and make sure all
// the pieces it had have their reference counter
@ -142,9 +141,9 @@ namespace libtorrent
// the number of peers that belong to this torrent
int num_peers() const { return m_connections.size(); }
// returns the number of connections this torrent has to
// the given peer_id (should be kept at max 1)
int num_connections(const peer_id& id) const;
// returns true if this torrent has a connection
// to a peer with the given peer_id
bool has_peer(const peer_id& id) const;
typedef std::vector<peer_connection*>::iterator peer_iterator;
typedef std::vector<peer_connection*>::const_iterator peer_const_iterator;
@ -270,7 +269,6 @@ namespace libtorrent
// from the tracker
int m_duration;
std::string m_failed;
std::vector<peer_connection*> m_connections;
// -----------------------------
@ -285,6 +283,10 @@ namespace libtorrent
int m_last_working_tracker;
int m_currently_trying_tracker;
// this is a counter that is increased every
// second, and when it reaches 10, the policy::pulse()
// is called and the time scaler is reset to 0.
int m_time_scaler;
};
}

View File

@ -122,6 +122,8 @@ namespace libtorrent
const std::string& name() const { return m_name; }
void print(std::ostream& os) const;
void convert_file_names();
entry::integer_type piece_size(unsigned int index) const
{
if (index == num_pieces()-1)

View File

@ -59,9 +59,9 @@ namespace libtorrent {
{
boost::mutex::scoped_lock lock(m_mutex);
assert(pending());
assert(!m_alerts.empty());
alert* result(m_alerts.front());
alert* result = m_alerts.front();
m_alerts.pop();
return std::auto_ptr<alert>(result);
}

View File

@ -86,6 +86,7 @@ libtorrent::peer_connection::peer_connection(
, m_selector(sel)
, m_socket(s)
, m_torrent(t)
, m_attached_to_torrent(true)
, m_ses(ses)
, m_active(true)
, m_added_to_selector(false)
@ -130,6 +131,7 @@ libtorrent::peer_connection::peer_connection(
, m_selector(sel)
, m_socket(s)
, m_torrent(0)
, m_attached_to_torrent(0)
, m_ses(ses)
, m_active(false)
, m_added_to_selector(false)
@ -159,7 +161,11 @@ libtorrent::peer_connection::peer_connection(
libtorrent::peer_connection::~peer_connection()
{
m_selector.remove(m_socket);
if (m_torrent) m_torrent->remove_peer(this);
if (m_attached_to_torrent)
{
assert(m_torrent != 0);
m_torrent->remove_peer(this);
}
}
void libtorrent::peer_connection::set_send_quota(int num_bytes)
@ -715,13 +721,17 @@ void libtorrent::peer_connection::send_have(int index)
void libtorrent::peer_connection::receive_data()
{
assert(!m_socket->is_blocking());
assert(m_packet_size > 0);
for(;;)
{
// m_socket->set_blocking(false);
assert(m_packet_size > 0);
int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos);
// connection closed
if (received == 0) throw network_error(0);
if (received == 0)
{
throw network_error(0);
}
// an error
if (received < 0)
@ -754,6 +764,14 @@ void libtorrent::peer_connection::receive_data()
m_state = read_protocol_string;
m_recv_buffer.resize(m_packet_size);
m_recv_pos = 0;
if (m_packet_size == 0)
{
#ifndef NDEBUG
(*m_logger) << "incorrect protocol length\n";
#endif
throw network_error(0);
}
break;
@ -765,7 +783,12 @@ void libtorrent::peer_connection::receive_data()
const char protocol_string[] = "BitTorrent protocol";
const int protocol_len = sizeof(protocol_string) - 1;
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), protocol_string))
{
#ifndef NDEBUG
(*m_logger) << "incorrect protocol name\n";
#endif
throw network_error(0);
}
m_state = read_info_hash;
m_packet_size = 28;
@ -800,7 +823,6 @@ void libtorrent::peer_connection::receive_data()
#endif
throw network_error(0);
}
m_torrent->attach_peer(this);
// assume the other end has no pieces
m_have_piece.resize(m_torrent->torrent_file().num_pieces());
@ -855,13 +877,18 @@ void libtorrent::peer_connection::receive_data()
// check to make sure we don't have another connection with the same
// info_hash and peer_id. If we do. close this connection.
std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)m_peer_id.begin());
if (m_torrent->num_connections(m_peer_id) > 1)
if (m_torrent->has_peer(m_peer_id))
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " duplicate connection, closing\n";
#endif
throw network_error(0);
}
m_attached_to_torrent = true;
m_torrent->attach_peer(this);
assert(m_torrent->get_policy().has_connection(this));
}
m_state = read_packet_size;
@ -900,6 +927,7 @@ void libtorrent::peer_connection::receive_data()
m_recv_buffer.resize(m_packet_size);
}
m_recv_pos = 0;
assert(m_packet_size > 0);
break;
case read_packet:
@ -917,11 +945,13 @@ void libtorrent::peer_connection::receive_data()
m_packet_size = 4;
m_recv_buffer.resize(4);
m_recv_pos = 0;
assert(m_packet_size > 0);
break;
}
}
}
}
assert(m_packet_size > 0);
}

View File

@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include <cmath>
#include <algorithm>
#include "libtorrent/piece_picker.hpp"
@ -40,8 +41,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_connection.hpp"
#endif
#if defined(_MSC_VER)
#if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) {} else for
namespace std
{
template<class T>
inline T min(T a, T b) { return a<b?a:b; }
}
#endif
namespace libtorrent
@ -85,7 +91,7 @@ namespace libtorrent
m_piece_info[peer_count].push_back(index);
}
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
// TODO: random_shuffle
}
@ -299,7 +305,7 @@ namespace libtorrent
move(true, m_piece_map[index].peer_count, m_piece_map[index].index);
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
}
@ -356,7 +362,7 @@ namespace libtorrent
assert(info_index != 0xffffff);
remove(m_piece_map[index].downloading, peer_count, info_index);
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
}
@ -367,7 +373,7 @@ namespace libtorrent
assert(pieces.size() == m_piece_map.size());
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
// free refers to pieces that are free to download, noone else
@ -502,7 +508,7 @@ namespace libtorrent
void piece_picker::mark_as_downloading(piece_block block, const peer_id& peer)
{
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
assert(block.piece_index < m_piece_map.size());
assert(block.block_index < blocks_in_piece(block.piece_index));
@ -529,14 +535,14 @@ namespace libtorrent
i->requested_blocks[block.block_index] = 1;
}
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
}
void piece_picker::mark_as_finished(piece_block block, const peer_id& peer)
{
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
assert(block.piece_index < m_piece_map.size());
assert(block.block_index < blocks_in_piece(block.piece_index));
@ -564,7 +570,7 @@ namespace libtorrent
i->finished_blocks[block.block_index] = 1;
}
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
}
/*
@ -610,7 +616,7 @@ namespace libtorrent
void piece_picker::abort_download(piece_block block)
{
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
assert(block.piece_index < m_piece_map.size());
@ -643,7 +649,7 @@ namespace libtorrent
move(true, m_piece_map[block.piece_index].peer_count, m_piece_map[block.piece_index].index);
}
#ifndef NDEBUG
integrity_check();
// integrity_check();
#endif
}

View File

@ -32,6 +32,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "libtorrent/policy.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/socket.hpp"
@ -137,7 +139,7 @@ namespace
peer_connection* peer = 0;
float down_speed = -1.f;
// find the peer with the lowest download
// speed that also has a piece thatt this
// speed that also has a piece that this
// peer could send us
for (torrent::peer_iterator i = t.begin();
i != t.end();
@ -171,6 +173,7 @@ namespace
num_requests--;
}
}
namespace libtorrent
@ -197,14 +200,6 @@ namespace libtorrent
TODO: to implement choking/unchoking we need a list with all
connected peers. Something like this:
struct peer
{
peer_id id;
boost::posix_time::ptime last_optimistically_unchoked;
float average_down_rate;
boost::weak_ptr<peer_connection> connection;
};
*/
@ -213,21 +208,92 @@ namespace libtorrent
, m_torrent(t)
{}
// this is called when a connection is made, before any
// handshake (it's possible to ban certain ip:s).
bool policy::accept_connection(const address& remote)
void policy::pulse()
{
m_num_peers++;
return true;
using namespace boost::posix_time;
// remove old disconnected peers from the list
m_peers.erase(
std::remove_if(m_peers.begin()
, m_peers.end()
, old_disconnected_peer())
, m_peers.end());
// choke peers that have leeched too much without giving anything back
for (std::vector<peer>::iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{
boost::shared_ptr<peer_connection> c = i->connection.lock();
if (c.get() == 0) continue;
int downloaded = i->prev_amount_download + c->statistics().total_download();
int uploaded = i->prev_amount_upload + c->statistics().total_upload();
if (uploaded - downloaded > m_torrent->torrent_file().piece_length()
&& !c->is_choked())
{
// if we have uploaded more than a piece for free, choke peer and
// wait until we catch up with our download.
c->choke();
}
else if (uploaded - downloaded <= m_torrent->block_size()
&& c->is_choked() && c->is_peer_interested())
{
// we have catched up. We have now shared the same amount
// to eachother. Unchoke this peer.
c->unchoke();
}
}
}
void policy::new_connection(const boost::weak_ptr<peer_connection>& c)
{
boost::shared_ptr<peer_connection> con = c.lock();
assert(con.get() != 0);
if (con.get() == 0) return;
std::vector<peer>::iterator i
= std::find(m_peers.begin(), m_peers.end(), con->get_peer_id());
if (i == m_peers.end())
{
// we don't have ny info about this peer.
// add a new entry
peer p(con->get_peer_id());
m_peers.push_back(p);
i = m_peers.end()-1;
}
else
{
assert(i->connection.expired());
}
i->connected = boost::posix_time::second_clock::local_time();
i->connection = c;
}
void policy::peer_from_tracker(const address& remote, const peer_id& id)
{
try
{
m_torrent->connect_to_peer(remote, id);
m_num_peers++;
std::vector<peer>::iterator i = std::find(m_peers.begin(), m_peers.end(), id);
if (i == m_peers.end())
{
// we don't have ny info about this peer.
// add a new entry
peer p(id);
m_peers.push_back(p);
i = m_peers.end()-1;
}
else if (!i->connection.expired())
{
// this means we're already connected
// to this peer. don't connect to
// it again.
return;
}
i->connected = boost::posix_time::second_clock::local_time();
i->connection = m_torrent->connect_to_peer(remote, id);
}
catch(network_error&) {}
}
@ -237,9 +303,9 @@ namespace libtorrent
// anything for a while
void policy::choked(peer_connection& c)
{
c.choke();
}
// TODO: the peer_connection argument here should be removed.
void policy::piece_finished(peer_connection& c, int index, bool successfully_verified)
{
// TODO: if verification failed, mark the peers that were involved
@ -248,8 +314,8 @@ namespace libtorrent
void policy::block_finished(peer_connection& c, piece_block b)
{
if (c.has_peer_choked()) return;
request_a_block(*m_torrent, c);
// if the peer hasn't choked us, ask for another piece
if (!c.has_peer_choked()) request_a_block(*m_torrent, c);
}
// this is called when we are unchoked by a peer
@ -257,21 +323,33 @@ namespace libtorrent
// data from now on
void policy::unchoked(peer_connection& c)
{
c.unchoke();
if (c.is_interesting()) request_a_block(*m_torrent, c);
if (c.is_interesting())
{
request_a_block(*m_torrent, c);
}
}
void policy::interested(peer_connection& c)
{
c.unchoke();
// if we're interested in the peer, we unchoke it
// and hopes it will unchoke us too
}
void policy::not_interested(peer_connection& c)
{
}
// this is called whenever a peer connection is closed
void policy::connection_closed(const peer_connection& c)
{
std::vector<peer>::iterator i
= std::find(m_peers.begin(), m_peers.end(), c.get_peer_id());
assert(i != m_peers.end());
i->connected = boost::posix_time::second_clock::local_time();
i->prev_amount_download += c.statistics().total_download();
i->prev_amount_upload += c.statistics().total_upload();
}
void policy::peer_is_interesting(peer_connection& c)
@ -280,4 +358,11 @@ namespace libtorrent
if (c.has_peer_choked()) return;
request_a_block(*m_torrent, c);
}
#ifndef NDEBUG
bool policy::has_connection(const peer_connection* p)
{
return std::find(m_peers.begin(), m_peers.end(), p->get_peer_id()) != m_peers.end();
}
#endif
}

View File

@ -105,7 +105,7 @@ namespace libtorrent
std::make_pair(t->info_hash, t->torrent_ptr)).first;
}
}
catch(const boost::filesystem::filesystem_error& e)
catch(const std::exception& e)
{
#ifndef NDEBUG
std::cerr << "error while checking files: " << e.what() << "\n";
@ -206,40 +206,26 @@ namespace libtorrent
m_selector.monitor_readability(listener);
m_selector.monitor_errors(listener);
/*
// temp
const peer& p = *m_peer_list.begin();
boost::shared_ptr<libtorrent::socket> s(new socket(socket::tcp, false));
address a(p.ip, p.port);
s->connect(a);
m_connections.insert(std::make_pair(s, peer_connection(this, s, p.id)));
m_selector.monitor_readability(s);
m_selector.monitor_errors(s);
// ~temp
*/
std::vector<boost::shared_ptr<socket> > readable_clients;
std::vector<boost::shared_ptr<socket> > writable_clients;
std::vector<boost::shared_ptr<socket> > error_clients;
boost::posix_time::ptime timer = boost::posix_time::second_clock::local_time();
#ifndef NDEBUG
int loops_per_second = 0;
#endif
for(;;)
{
#ifndef NDEBUG
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();
++i)
{
assert(i->second->has_data() == m_selector.is_writability_monitored(i->first));
}
assert_invariant();
loops_per_second++;
#endif
// if nothing happens within 500000 microseconds (0.5 seconds)
// do the loop anyway to check if anything else has changed
// (*m_logger) << "sleeping\n";
// << "sleeping\n";
m_selector.wait(500000, readable_clients, writable_clients, error_clients);
boost::mutex::scoped_lock l(m_mutex);
@ -263,6 +249,9 @@ namespace libtorrent
break;
}
#ifndef NDEBUG
assert_invariant();
#endif
// ************************
// RECEIVE SOCKETS
// ************************
@ -286,18 +275,18 @@ namespace libtorrent
// TODO: the send buffer size should be controllable from the outside
// s->set_send_bufsize(2048);
// TODO: add some possibility to filter IP:s
// TODO: filter ip:s
boost::shared_ptr<peer_connection> c(
new peer_connection(this, m_selector, s));
if (m_upload_rate != -1) c->set_send_quota(0);
m_connections.insert(std::make_pair(s, c));
m_selector.monitor_readability(s);
m_selector.monitor_errors(s);
}
continue;
}
connection_map::iterator p = m_connections.find(*i);
if(p == m_connections.end())
{
@ -320,6 +309,10 @@ namespace libtorrent
}
}
#ifndef NDEBUG
assert_invariant();
#endif
// ************************
// SEND SOCKETS
// ************************
@ -373,12 +366,7 @@ namespace libtorrent
}
#ifndef NDEBUG
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();
++i)
{
assert(i->second->has_data() == m_selector.is_writability_monitored(i->first));
}
assert_invariant();
#endif
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
@ -389,6 +377,11 @@ namespace libtorrent
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
// ************************
#ifndef NDEBUG
// std::cout << "\n\nloops: " << loops_per_second << "\n";
loops_per_second = 0;
#endif
// distribute the maximum upload rate among the peers
// TODO: implement an intelligent algorithm that
// will shift bandwidth from the peers that can't
@ -458,6 +451,8 @@ namespace libtorrent
i->second->generate_tracker_request(m_listen_port),
boost::get_pointer(i->second));
}
i->second->second_tick();
++i;
}
m_tracker_manager.tick();
@ -527,6 +522,23 @@ namespace libtorrent
}
#endif
#ifndef NDEBUG
void session_impl::assert_invariant()
{
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();
++i)
{
assert(i->second->has_data() == m_selector.is_writability_monitored(i->first));
if (i->second->associated_torrent())
{
assert(i->second->associated_torrent()
->get_policy().has_connection(boost::get_pointer(i->second)));
}
}
}
#endif
}
session::session(int listen_port, const std::string& fingerprint)

View File

@ -156,7 +156,7 @@ void libtorrent::piece_file::reopen()
m_file.close();
m_file.clear();
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
if (m_mode == in) m_file.seekg(m_file_offset, std::ios_base::beg);
else m_file.seekp(m_file_offset, std::ios_base::beg);
@ -242,7 +242,7 @@ void libtorrent::piece_file::open(storage* s, int index, open_mode o, int seek_o
m_file.clear();
m_file_mode = m;
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
if (m_mode == in) m_file.seekg(m_file_offset, std::ios_base::beg);
else m_file.seekp(m_file_offset, std::ios_base::beg);
@ -294,7 +294,7 @@ void libtorrent::piece_file::open(storage* s, int index, open_mode o, int seek_o
m_file.clear();
m_file_mode = m;
m_file.open(p.native_file_string().c_str(), m_file_mode);
m_file.open(p, m_file_mode);
// std::cout << "opening file: '" << p.native_file_string() << "'\n";
if (m_file.fail())
{
@ -373,6 +373,7 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
left_to_read -= read_bytes;
buf_pos += read_bytes;
assert(buf_pos >= 0);
m_file_offset += read_bytes;
m_piece_offset += read_bytes;
@ -385,7 +386,7 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
m_file_offset = 0;
m_file.close();
m_file.clear();
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
}
}
@ -413,11 +414,14 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
int available = std::min(static_cast<entry::integer_type>(m_file_iter->size - m_file_offset),
static_cast<entry::integer_type>(left_to_read));
assert(buf_pos >= 0);
m_file.read(buf + buf_pos, available);
int read = m_file.gcount();
assert(read > 0);
left_to_read -= read;
read_total += read;
buf_pos += read;
assert(buf_pos >= 0);
m_file_offset += read;
m_piece_offset += read;
@ -432,7 +436,7 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
m_file_offset = 0;
m_file.close();
m_file.clear();
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
// std::cout << "opening file: '" << path.native_file_string() << "'\n";
if (m_file.fail())
{
@ -503,10 +507,13 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
if (m_file_offset + write_bytes > m_file_iter->size)
write_bytes = m_file_iter->size - m_file_offset;
assert(buf_pos >= 0);
assert(write_bytes > 0);
m_file.write(buf + buf_pos, write_bytes);
left_to_write -= write_bytes;
buf_pos += write_bytes;
assert(buf_pos >= 0);
m_file_offset += write_bytes;
m_piece_offset += write_bytes;
@ -522,12 +529,12 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
m_file_offset = 0;
m_file.close();
m_file.clear();
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
}
}
#if 0 // old implementation
/*
assert(m_mode == out);
int left_to_write = size;
@ -558,7 +565,7 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
m_file_offset = 0;
m_file.close();
m_file.open(path.native_file_string().c_str(), m_file_mode);
m_file.open(path, m_file_mode);
// std::cout << "opening file: '" << path.native_file_string() << "'\n";
if (m_file.fail())
{
@ -567,7 +574,7 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
}
}
} while (left_to_write > 0);
*/
#endif
}
@ -608,7 +615,7 @@ void libtorrent::piece_file::seek_forward(int step, bool lock_)
path /= m_file_iter->filename;
m_file.close();
m_file.open(path.native_file_string().c_str(), std::ios_base::in | std::ios_base::binary);
m_file.open(path, std::ios_base::in | std::ios_base::binary);
}
m_file_offset += left_to_seek;
@ -771,9 +778,9 @@ void libtorrent::storage::allocate_pieces(int num)
fs::ofstream out;
if (fs::exists(path))
out.open(path.native_file_string().c_str(), std::ios_base::binary | std::ios_base::in);
out.open(path, std::ios_base::binary | std::ios_base::in);
else
out.open(path.native_file_string().c_str(), std::ios_base::binary);
out.open(path, std::ios_base::binary);
// std::ofstream out((m_save_path / file_iter->path / file_iter->filename).native_file_string().c_str()
// , std::ios_base::binary | std::ios_base::in);
@ -831,7 +838,7 @@ entry::integer_type libtorrent::storage::piece_storage(int piece)
if (m_free_pieces.empty())
{
allocate_pieces(5000);
allocate_pieces(5);
assert(!m_free_pieces.empty());
}
@ -1182,7 +1189,7 @@ void libtorrent::storage::initialize_pieces(torrent* t,
{
in.close();
in.clear();
in.open(path.native_file_string().c_str(), std::ios_base::binary);
in.open(path, std::ios_base::binary);
changed_file = false;

View File

@ -128,6 +128,13 @@ namespace
return true;
}
bool operator()(const peer_connection* p) const
{
if (p->get_peer_id() != id) return false;
if (tor != p->associated_torrent()) return false;
return true;
}
const peer_id& id;
const torrent* tor;
};
@ -151,6 +158,7 @@ namespace libtorrent
(torrent_file.total_size()+m_block_size-1)/m_block_size)
, m_last_working_tracker(0)
, m_currently_trying_tracker(0)
, m_time_scaler(0)
{
}
@ -219,16 +227,17 @@ namespace libtorrent
}
int torrent::num_connections(const peer_id& id) const
bool torrent::has_peer(const peer_id& id) const
{
int num = 0;
for (detail::session_impl::connection_map::const_iterator i = m_ses->m_connections.begin();
i != m_ses->m_connections.end();
++i)
{
if (i->second->get_peer_id() == id && i->second->associated_torrent() == this) ++num;
}
return num;
assert(std::count_if(m_connections.begin()
, m_connections.end()
, find_peer(id, this)) <= 1);
return std::find_if(
m_connections.begin()
, m_connections.end()
, find_peer(id, this))
!= m_connections.end();
}
void torrent::announce_piece(int index)
@ -236,10 +245,6 @@ namespace libtorrent
m_picker.we_have(index);
for (std::vector<peer_connection*>::iterator i = m_connections.begin(); i != m_connections.end(); ++i)
(*i)->announce_piece(index);
#ifndef NDEBUG
m_picker.integrity_check(this);
#endif
}
std::string torrent::generate_tracker_request(int port)
@ -335,7 +340,7 @@ namespace libtorrent
#endif
}
void torrent::connect_to_peer(const address& a, const peer_id& id)
boost::weak_ptr<peer_connection> torrent::connect_to_peer(const address& a, const peer_id& id)
{
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
// TODO: the send buffer size should be controllable from the outside
@ -350,10 +355,30 @@ namespace libtorrent
if (m_ses->m_upload_rate != -1) c->set_send_quota(0);
detail::session_impl::connection_map::iterator p =
m_ses->m_connections.insert(std::make_pair(s, c)).first;
attach_peer(boost::get_pointer(p->second));
// add the newly connected peer to this torrent's peer list
assert(std::find(m_connections.begin()
, m_connections.end()
, boost::get_pointer(p->second))
== m_connections.end());
m_connections.push_back(boost::get_pointer(p->second));
m_ses->m_selector.monitor_readability(s);
m_ses->m_selector.monitor_errors(s);
// std::cout << "connecting to: " << a.as_string() << ":" << a.port() << "\n";
return c;
}
void torrent::attach_peer(peer_connection* p)
{
assert(std::find(m_connections.begin(), m_connections.end(), p) == m_connections.end());
m_connections.push_back(p);
detail::session_impl::connection_map::iterator i
= m_ses->m_connections.find(p->get_socket());
assert(i != m_ses->m_connections.end());
m_policy->new_connection(i->second);
}
void torrent::close_all_connections()
@ -412,6 +437,16 @@ namespace libtorrent
#endif
}
void torrent::second_tick()
{
m_time_scaler++;
if (m_time_scaler >= 10)
{
m_time_scaler = 0;
m_policy->pulse();
}
}
torrent_status torrent::status() const
{
torrent_status st;

View File

@ -165,6 +165,8 @@ namespace libtorrent
p.id = peer->get_peer_id();
p.ip = peer->get_socket()->sender();
// TODO: add the prev_amount_downloaded and prev_amount_uploaded
// from the peer list in the policy
p.total_download = statistics.total_download();
p.total_upload = statistics.total_upload();
@ -172,7 +174,7 @@ namespace libtorrent
p.flags = 0;
if (peer->is_interesting()) p.flags |= peer_info::interesting;
if (peer->has_choked()) p.flags |= peer_info::choked;
if (peer->is_choked()) p.flags |= peer_info::choked;
if (peer->is_peer_interested()) p.flags |= peer_info::remote_interested;
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;

View File

@ -204,6 +204,35 @@ namespace libtorrent
std::copy(hash_string.begin() + i*20, hash_string.begin() + (i+1)*20, m_piece_hash[i].begin());
}
void torrent_info::convert_file_names()
{
for (std::vector<file>::iterator i = m_files.begin(); i != m_files.end(); ++i)
{
// replace all dots in directory names with underscores
std::string& path = i->path;
std::string& filename = i->filename;
for (std::string::iterator c = path.begin(); c != path.end(); ++c)
{
if (*c == '.') *c = '_';
if (*c == ' ') *c = '_';
if (*c == '[') *c = '_';
if (*c == ']') *c = '_';
}
// replace all dots, but the last one,
// in file names with underscores
std::string::reverse_iterator last_dot
= std::find(filename.rbegin(), filename.rend(), '.');
for (std::string::reverse_iterator c = filename.rbegin(); c != filename.rend(); ++c)
{
if (c != last_dot && *c == '.') *c = '_';
if (*c == ' ') *c = '_';
if (*c == '[') *c = '_';
if (*c == ']') *c = '_';
}
}
}
int torrent_info::prioritize_tracker(int index)
{
if (index > m_urls.size()) return m_urls.size()-1;