*** empty log message ***
This commit is contained in:
parent
f21d6a0f7f
commit
6402fd4a14
|
@ -66,6 +66,11 @@ namespace libtorrent
|
|||
struct session_impl;
|
||||
}
|
||||
|
||||
struct protocol_error: std::runtime_error
|
||||
{
|
||||
protocol_error(const std::string& msg): std::runtime_error(msg) {};
|
||||
};
|
||||
|
||||
struct peer_request
|
||||
{
|
||||
int piece;
|
||||
|
@ -181,13 +186,28 @@ namespace libtorrent
|
|||
// peer.
|
||||
int send_quota() const { return m_send_quota; }
|
||||
|
||||
void received_valid_data()
|
||||
{
|
||||
m_trust_points++;
|
||||
if (m_trust_points > 20) m_trust_points = 20;
|
||||
}
|
||||
|
||||
void received_invalid_data()
|
||||
{
|
||||
m_trust_points--;
|
||||
if (m_trust_points < 5) m_trust_points = 5;
|
||||
}
|
||||
|
||||
int trust_points() const
|
||||
{ return m_trust_points; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
boost::shared_ptr<logger> m_logger;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
bool dispatch_message();
|
||||
void dispatch_message();
|
||||
void send_buffer_updated();
|
||||
|
||||
void send_bitfield();
|
||||
|
@ -314,6 +334,14 @@ namespace libtorrent
|
|||
// speed
|
||||
int m_send_quota;
|
||||
int m_send_quota_left;
|
||||
|
||||
// for every valid piece we receive where this
|
||||
// peer was one of the participants, we increase
|
||||
// this value. For every invalid piece we receive
|
||||
// where this peer was a participant, we decrease
|
||||
// this value. If it sinks below a threshold, its
|
||||
// considered a bad peer and will be banned.
|
||||
int m_trust_points;
|
||||
};
|
||||
|
||||
// this is called each time this peer generates some
|
||||
|
|
|
@ -62,7 +62,8 @@ namespace libtorrent
|
|||
void pulse();
|
||||
|
||||
// called when an incoming connection is accepted
|
||||
void new_connection(const boost::weak_ptr<peer_connection>& c);
|
||||
// return false if the connection closed
|
||||
bool new_connection(const boost::weak_ptr<peer_connection>& c);
|
||||
|
||||
// this is called once for every peer we get from
|
||||
// the tracker
|
||||
|
@ -71,6 +72,10 @@ namespace libtorrent
|
|||
// the given connection was just closed
|
||||
void connection_closed(const peer_connection& c);
|
||||
|
||||
// is called when a peer is believed to have
|
||||
// sent invalid data
|
||||
void ban_peer(const peer_connection& c);
|
||||
|
||||
// the peer has got at least one interesting piece
|
||||
void peer_is_interesting(peer_connection& c);
|
||||
|
||||
|
@ -105,6 +110,7 @@ namespace libtorrent
|
|||
, optimistic_unchokes(0)
|
||||
, prev_amount_upload(0)
|
||||
, prev_amount_download(0)
|
||||
, banned(false)
|
||||
{}
|
||||
|
||||
bool operator==(const peer_id& pid) const
|
||||
|
@ -140,6 +146,9 @@ namespace libtorrent
|
|||
int prev_amount_upload;
|
||||
int prev_amount_download;
|
||||
|
||||
// is set to true if this peer has been banned
|
||||
bool banned;
|
||||
|
||||
// if the peer is connected now, this
|
||||
// will refer to a valid peer_connection
|
||||
boost::weak_ptr<peer_connection> connection;
|
||||
|
|
|
@ -216,6 +216,11 @@ namespace libtorrent
|
|||
|
||||
piece_picker& picker() { return m_picker; }
|
||||
|
||||
// this is called from the peer_connection
|
||||
// each time a piece has failed the hash
|
||||
// test
|
||||
void piece_failed(int index);
|
||||
|
||||
// DEBUG
|
||||
#ifndef NDEBUG
|
||||
logger* spawn_logger(const char* title);
|
||||
|
|
|
@ -225,11 +225,11 @@ void libtorrent::peer_connection::send_handshake()
|
|||
send_buffer_updated();
|
||||
}
|
||||
|
||||
bool libtorrent::peer_connection::dispatch_message()
|
||||
void libtorrent::peer_connection::dispatch_message()
|
||||
{
|
||||
int packet_type = m_recv_buffer[0];
|
||||
if (packet_type > 8 || packet_type < 0)
|
||||
return false;
|
||||
throw protocol_error("unknown message id");
|
||||
|
||||
switch (packet_type)
|
||||
{
|
||||
|
@ -295,7 +295,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
std::size_t index = read_int(&m_recv_buffer[1]);
|
||||
// if we got an invalid message, abort
|
||||
if (index >= m_have_piece.size())
|
||||
return false;
|
||||
throw protocol_error("have message with higher index than the number of pieces");
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n";
|
||||
|
@ -323,7 +323,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
case msg_bitfield:
|
||||
{
|
||||
if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8)
|
||||
return false;
|
||||
throw protocol_error("bitfield with invalid size");
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n";
|
||||
|
@ -390,7 +390,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " piece index invalid\n";
|
||||
#endif
|
||||
return false;
|
||||
throw protocol_error("invalid piece index in piece message");
|
||||
}
|
||||
int offset = read_int(&m_recv_buffer[5]);
|
||||
int len = m_packet_size - 9;
|
||||
|
@ -400,7 +400,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " offset < 0\n";
|
||||
#endif
|
||||
return false;
|
||||
throw protocol_error("offset < 0 in piece message");
|
||||
}
|
||||
|
||||
if (offset + len > m_torrent->torrent_file().piece_size(index))
|
||||
|
@ -408,7 +408,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n";
|
||||
#endif
|
||||
return false;
|
||||
throw protocol_error("piece message contains more data than the piece size");
|
||||
}
|
||||
|
||||
if (offset % m_torrent->block_size() != 0)
|
||||
|
@ -416,7 +416,7 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n";
|
||||
#endif
|
||||
return false;
|
||||
throw protocol_error("piece message contains unaligned offset");
|
||||
}
|
||||
/*
|
||||
piece_block req = m_download_queue.front();
|
||||
|
@ -471,6 +471,8 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
picker.mark_as_finished(block_finished, m_peer_id);
|
||||
|
||||
m_torrent->get_policy().block_finished(*this, block_finished);
|
||||
|
||||
// did we just finish the piece?
|
||||
if (picker.is_piece_finished(index))
|
||||
{
|
||||
|
@ -483,26 +485,10 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
std::cout << "hash-test failed. Some of these peers sent invalid data:\n";
|
||||
std::vector<peer_id> downloaders;
|
||||
picker.get_downloaders(downloaders, index);
|
||||
std::copy(downloaders.begin(), downloaders.end(), std::ostream_iterator<peer_id>(std::cout, "\n"));
|
||||
#endif
|
||||
// we have to let the piece_picker know that
|
||||
// this piece failed the check as it can restore it
|
||||
// and mark it as being interesting for download
|
||||
// TODO: do this more intelligently! and keep track
|
||||
// of how much crap (data that failed hash-check) and
|
||||
// how much redundant data we have downloaded
|
||||
// if some clients has sent more than one piece
|
||||
// start with redownloading the pieces that the client
|
||||
// that has sent the least number of pieces
|
||||
picker.restore_piece(index);
|
||||
m_torrent->piece_failed(index);
|
||||
}
|
||||
m_torrent->get_policy().piece_finished(*this, index, verified);
|
||||
}
|
||||
m_torrent->get_policy().block_finished(*this, block_finished);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -534,8 +520,6 @@ bool libtorrent::peer_connection::dispatch_message()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void libtorrent::peer_connection::cancel_block(piece_block block)
|
||||
|
@ -932,14 +916,9 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
case read_packet:
|
||||
|
||||
if (!dispatch_message())
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " received invalid packet\n";
|
||||
#endif
|
||||
// invalid message
|
||||
throw network_error(0);
|
||||
}
|
||||
// TODO: dispatch should throw instead of returning status
|
||||
// and instead of throwing network_error, throw protocol_error
|
||||
dispatch_message();
|
||||
|
||||
m_state = read_packet_size;
|
||||
m_packet_size = 4;
|
||||
|
|
|
@ -197,9 +197,11 @@ namespace libtorrent
|
|||
void peer_connection::request_piece(int index);
|
||||
const std::vector<int>& peer_connection::download_queue();
|
||||
|
||||
TODO: to implement choking/unchoking we need a list with all
|
||||
connected peers. Something like this:
|
||||
TODO: implement a limit of the number of unchoked peers.
|
||||
|
||||
TODO: implement some kind of limit of the number of sockets
|
||||
opened, to use for systems where a user has a limited number
|
||||
of open file descriptors
|
||||
*/
|
||||
|
||||
|
||||
|
@ -238,6 +240,10 @@ namespace libtorrent
|
|||
else if (uploaded - downloaded <= m_torrent->block_size()
|
||||
&& c->is_choked() && c->is_peer_interested())
|
||||
{
|
||||
// TODO: if we're not interested in this peer
|
||||
// we should only unchoke it if it' its turn
|
||||
// to be optimistically unchoked.
|
||||
|
||||
// we have catched up. We have now shared the same amount
|
||||
// to eachother. Unchoke this peer.
|
||||
c->unchoke();
|
||||
|
@ -245,11 +251,19 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void policy::new_connection(const boost::weak_ptr<peer_connection>& c)
|
||||
void policy::ban_peer(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->banned = true;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
if (con.get() == 0) return false;
|
||||
|
||||
std::vector<peer>::iterator i
|
||||
= std::find(m_peers.begin(), m_peers.end(), con->get_peer_id());
|
||||
|
@ -264,10 +278,12 @@ namespace libtorrent
|
|||
else
|
||||
{
|
||||
assert(i->connection.expired());
|
||||
if (i->banned) return false;
|
||||
}
|
||||
|
||||
i->connected = boost::posix_time::second_clock::local_time();
|
||||
i->connection = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
void policy::peer_from_tracker(const address& remote, const peer_id& id)
|
||||
|
@ -291,11 +307,14 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
if (i->banned) return;
|
||||
|
||||
i->connected = boost::posix_time::second_clock::local_time();
|
||||
i->connection = m_torrent->connect_to_peer(remote, id);
|
||||
|
||||
}
|
||||
catch(network_error&) {}
|
||||
catch(protocol_error&) {}
|
||||
}
|
||||
|
||||
// this is called when we are choked by a peer
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace libtorrent
|
|||
{
|
||||
listener->listen(m_listen_port, 5);
|
||||
}
|
||||
catch(network_error&)
|
||||
catch(std::exception&)
|
||||
{
|
||||
if (m_listen_port > max_port)
|
||||
throw;
|
||||
|
@ -299,7 +299,7 @@ namespace libtorrent
|
|||
// (*m_logger) << "readable: " << p->first->sender().as_string() << "\n";
|
||||
p->second->receive_data();
|
||||
}
|
||||
catch(network_error&)
|
||||
catch(std::exception&)
|
||||
{
|
||||
// the connection wants to disconnect for some reason, remove it
|
||||
// from the connection-list
|
||||
|
@ -338,7 +338,7 @@ namespace libtorrent
|
|||
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
|
||||
p->second->send_data();
|
||||
}
|
||||
catch(network_error&)
|
||||
catch(std::exception&)
|
||||
{
|
||||
// the connection wants to disconnect for some reason, remove it
|
||||
// from the connection-list
|
||||
|
|
|
@ -366,6 +366,7 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
|
|||
int read_bytes = left_to_read;
|
||||
if (m_file_offset + read_bytes > m_file_iter->size)
|
||||
read_bytes = m_file_iter->size - m_file_offset;
|
||||
assert(read_bytes > 0);
|
||||
|
||||
m_file.read(buf + buf_pos, read_bytes);
|
||||
|
||||
|
@ -505,7 +506,10 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
|
|||
{
|
||||
int write_bytes = left_to_write;
|
||||
if (m_file_offset + write_bytes > m_file_iter->size)
|
||||
{
|
||||
assert(m_file_iter->size > m_file_offset);
|
||||
write_bytes = m_file_iter->size - m_file_offset;
|
||||
}
|
||||
|
||||
assert(buf_pos >= 0);
|
||||
assert(write_bytes > 0);
|
||||
|
@ -515,6 +519,7 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
|
|||
buf_pos += write_bytes;
|
||||
assert(buf_pos >= 0);
|
||||
m_file_offset += write_bytes;
|
||||
assert(m_file_offset < m_file_iter->size);
|
||||
m_piece_offset += write_bytes;
|
||||
|
||||
if (left_to_write > 0)
|
||||
|
@ -522,6 +527,7 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
|
|||
++m_file_iter;
|
||||
|
||||
assert(m_file_iter != m_storage->m_torrent_file->end_files());
|
||||
assert(m_file_iter->size > m_file_offset);
|
||||
|
||||
boost::filesystem::path path = m_storage->m_save_path /
|
||||
m_file_iter->path / m_file_iter->filename;
|
||||
|
|
|
@ -240,8 +240,69 @@ namespace libtorrent
|
|||
!= m_connections.end();
|
||||
}
|
||||
|
||||
void torrent::piece_failed(int index)
|
||||
{
|
||||
std::vector<peer_id> downloaders;
|
||||
m_picker.get_downloaders(downloaders, index);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::cout << "hash-test failed. Some of these peers sent invalid data:\n";
|
||||
std::copy(downloaders.begin(), downloaders.end(), std::ostream_iterator<peer_id>(std::cout, "\n"));
|
||||
#endif
|
||||
|
||||
// decrease the trust point of all peers that sent
|
||||
// parts of this piece.
|
||||
// TODO: implement this loop more efficient
|
||||
for (std::vector<peer_connection*>::iterator i = m_connections.begin();
|
||||
i != m_connections.end();
|
||||
++i)
|
||||
{
|
||||
if (std::find(downloaders.begin(), downloaders.end(), (*i)->get_peer_id())
|
||||
!= downloaders.end())
|
||||
{
|
||||
(*i)->received_invalid_data();
|
||||
if ((*i)->trust_points() <= -5)
|
||||
{
|
||||
// we don't trust this peer anymore
|
||||
// ban it.
|
||||
m_policy->ban_peer(*(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have to let the piece_picker know that
|
||||
// this piece failed the check as it can restore it
|
||||
// and mark it as being interesting for download
|
||||
// TODO: do this more intelligently! and keep track
|
||||
// of how much crap (data that failed hash-check) and
|
||||
// how much redundant data we have downloaded
|
||||
// if some clients has sent more than one piece
|
||||
// start with redownloading the pieces that the client
|
||||
// that has sent the least number of pieces
|
||||
m_picker.restore_piece(index);
|
||||
}
|
||||
|
||||
|
||||
void torrent::announce_piece(int index)
|
||||
{
|
||||
std::vector<peer_id> downloaders;
|
||||
m_picker.get_downloaders(downloaders, index);
|
||||
|
||||
// increase the trust point of all peers that sent
|
||||
// parts of this piece.
|
||||
// TODO: implement this loop more efficient
|
||||
for (std::vector<peer_connection*>::iterator i = m_connections.begin();
|
||||
i != m_connections.end();
|
||||
++i)
|
||||
{
|
||||
if (std::find(downloaders.begin(), downloaders.end(), (*i)->get_peer_id())
|
||||
!= downloaders.end())
|
||||
{
|
||||
(*i)->received_valid_data();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_picker.we_have(index);
|
||||
for (std::vector<peer_connection*>::iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||
(*i)->announce_piece(index);
|
||||
|
@ -378,7 +439,7 @@ namespace libtorrent
|
|||
= m_ses->m_connections.find(p->get_socket());
|
||||
assert(i != m_ses->m_connections.end());
|
||||
|
||||
m_policy->new_connection(i->second);
|
||||
if (!m_policy->new_connection(i->second)) throw network_error(0);
|
||||
}
|
||||
|
||||
void torrent::close_all_connections()
|
||||
|
|
|
@ -156,6 +156,11 @@ namespace libtorrent
|
|||
++i)
|
||||
{
|
||||
peer_connection* peer = *i;
|
||||
|
||||
// peers that hasn't finished the handshake should
|
||||
// not be included in this list
|
||||
if (peer->associated_torrent() == 0) continue;
|
||||
|
||||
v.push_back(peer_info());
|
||||
peer_info& p = v.back();
|
||||
|
||||
|
|
Loading…
Reference in New Issue