*** empty log message ***

This commit is contained in:
Arvid Norberg 2003-12-01 21:27:27 +00:00
parent f21d6a0f7f
commit 6402fd4a14
9 changed files with 157 additions and 45 deletions

View File

@ -66,6 +66,11 @@ namespace libtorrent
struct session_impl; struct session_impl;
} }
struct protocol_error: std::runtime_error
{
protocol_error(const std::string& msg): std::runtime_error(msg) {};
};
struct peer_request struct peer_request
{ {
int piece; int piece;
@ -181,13 +186,28 @@ namespace libtorrent
// peer. // peer.
int send_quota() const { return m_send_quota; } 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 #ifndef NDEBUG
boost::shared_ptr<logger> m_logger; boost::shared_ptr<logger> m_logger;
#endif #endif
private: private:
bool dispatch_message(); void dispatch_message();
void send_buffer_updated(); void send_buffer_updated();
void send_bitfield(); void send_bitfield();
@ -314,6 +334,14 @@ namespace libtorrent
// speed // speed
int m_send_quota; int m_send_quota;
int m_send_quota_left; 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 // this is called each time this peer generates some

View File

@ -62,7 +62,8 @@ namespace libtorrent
void pulse(); void pulse();
// called when an incoming connection is accepted // 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 // this is called once for every peer we get from
// the tracker // the tracker
@ -71,6 +72,10 @@ namespace libtorrent
// the given connection was just closed // the given connection was just closed
void connection_closed(const peer_connection& c); 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 // the peer has got at least one interesting piece
void peer_is_interesting(peer_connection& c); void peer_is_interesting(peer_connection& c);
@ -105,6 +110,7 @@ namespace libtorrent
, optimistic_unchokes(0) , optimistic_unchokes(0)
, prev_amount_upload(0) , prev_amount_upload(0)
, prev_amount_download(0) , prev_amount_download(0)
, banned(false)
{} {}
bool operator==(const peer_id& pid) const bool operator==(const peer_id& pid) const
@ -140,6 +146,9 @@ namespace libtorrent
int prev_amount_upload; int prev_amount_upload;
int prev_amount_download; int prev_amount_download;
// is set to true if this peer has been banned
bool banned;
// if the peer is connected now, this // if the peer is connected now, this
// will refer to a valid peer_connection // will refer to a valid peer_connection
boost::weak_ptr<peer_connection> connection; boost::weak_ptr<peer_connection> connection;

View File

@ -216,6 +216,11 @@ namespace libtorrent
piece_picker& picker() { return m_picker; } 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 // DEBUG
#ifndef NDEBUG #ifndef NDEBUG
logger* spawn_logger(const char* title); logger* spawn_logger(const char* title);

View File

@ -225,11 +225,11 @@ void libtorrent::peer_connection::send_handshake()
send_buffer_updated(); send_buffer_updated();
} }
bool libtorrent::peer_connection::dispatch_message() void libtorrent::peer_connection::dispatch_message()
{ {
int packet_type = m_recv_buffer[0]; int packet_type = m_recv_buffer[0];
if (packet_type > 8 || packet_type < 0) if (packet_type > 8 || packet_type < 0)
return false; throw protocol_error("unknown message id");
switch (packet_type) switch (packet_type)
{ {
@ -295,7 +295,7 @@ bool libtorrent::peer_connection::dispatch_message()
std::size_t index = read_int(&m_recv_buffer[1]); std::size_t index = read_int(&m_recv_buffer[1]);
// if we got an invalid message, abort // if we got an invalid message, abort
if (index >= m_have_piece.size()) if (index >= m_have_piece.size())
return false; throw protocol_error("have message with higher index than the number of pieces");
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n"; (*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n";
@ -323,7 +323,7 @@ bool libtorrent::peer_connection::dispatch_message()
case msg_bitfield: case msg_bitfield:
{ {
if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8) if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8)
return false; throw protocol_error("bitfield with invalid size");
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n"; (*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n";
@ -390,7 +390,7 @@ bool libtorrent::peer_connection::dispatch_message()
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece index invalid\n"; (*m_logger) << m_socket->sender().as_string() << " piece index invalid\n";
#endif #endif
return false; throw protocol_error("invalid piece index in piece message");
} }
int offset = read_int(&m_recv_buffer[5]); int offset = read_int(&m_recv_buffer[5]);
int len = m_packet_size - 9; int len = m_packet_size - 9;
@ -400,7 +400,7 @@ bool libtorrent::peer_connection::dispatch_message()
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " offset < 0\n"; (*m_logger) << m_socket->sender().as_string() << " offset < 0\n";
#endif #endif
return false; throw protocol_error("offset < 0 in piece message");
} }
if (offset + len > m_torrent->torrent_file().piece_size(index)) if (offset + len > m_torrent->torrent_file().piece_size(index))
@ -408,7 +408,7 @@ bool libtorrent::peer_connection::dispatch_message()
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n"; (*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n";
#endif #endif
return false; throw protocol_error("piece message contains more data than the piece size");
} }
if (offset % m_torrent->block_size() != 0) if (offset % m_torrent->block_size() != 0)
@ -416,7 +416,7 @@ bool libtorrent::peer_connection::dispatch_message()
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n"; (*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n";
#endif #endif
return false; throw protocol_error("piece message contains unaligned offset");
} }
/* /*
piece_block req = m_download_queue.front(); 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); picker.mark_as_finished(block_finished, m_peer_id);
m_torrent->get_policy().block_finished(*this, block_finished);
// did we just finish the piece? // did we just finish the piece?
if (picker.is_piece_finished(index)) if (picker.is_piece_finished(index))
{ {
@ -483,26 +485,10 @@ bool libtorrent::peer_connection::dispatch_message()
} }
else else
{ {
#ifndef NDEBUG m_torrent->piece_failed(index);
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->get_policy().piece_finished(*this, index, verified); m_torrent->get_policy().piece_finished(*this, index, verified);
} }
m_torrent->get_policy().block_finished(*this, block_finished);
break; break;
} }
@ -534,8 +520,6 @@ bool libtorrent::peer_connection::dispatch_message()
break; break;
} }
} }
return true;
} }
void libtorrent::peer_connection::cancel_block(piece_block block) void libtorrent::peer_connection::cancel_block(piece_block block)
@ -932,14 +916,9 @@ void libtorrent::peer_connection::receive_data()
case read_packet: case read_packet:
if (!dispatch_message()) // TODO: dispatch should throw instead of returning status
{ // and instead of throwing network_error, throw protocol_error
#ifndef NDEBUG dispatch_message();
(*m_logger) << m_socket->sender().as_string() << " received invalid packet\n";
#endif
// invalid message
throw network_error(0);
}
m_state = read_packet_size; m_state = read_packet_size;
m_packet_size = 4; m_packet_size = 4;

View File

@ -197,9 +197,11 @@ namespace libtorrent
void peer_connection::request_piece(int index); void peer_connection::request_piece(int index);
const std::vector<int>& peer_connection::download_queue(); const std::vector<int>& peer_connection::download_queue();
TODO: to implement choking/unchoking we need a list with all TODO: implement a limit of the number of unchoked peers.
connected peers. Something like this:
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() else if (uploaded - downloaded <= m_torrent->block_size()
&& c->is_choked() && c->is_peer_interested()) && 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 // we have catched up. We have now shared the same amount
// to eachother. Unchoke this peer. // to eachother. Unchoke this peer.
c->unchoke(); 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(); boost::shared_ptr<peer_connection> con = c.lock();
assert(con.get() != 0); assert(con.get() != 0);
if (con.get() == 0) return; if (con.get() == 0) return false;
std::vector<peer>::iterator i std::vector<peer>::iterator i
= std::find(m_peers.begin(), m_peers.end(), con->get_peer_id()); = std::find(m_peers.begin(), m_peers.end(), con->get_peer_id());
@ -264,10 +278,12 @@ namespace libtorrent
else else
{ {
assert(i->connection.expired()); assert(i->connection.expired());
if (i->banned) return false;
} }
i->connected = boost::posix_time::second_clock::local_time(); i->connected = boost::posix_time::second_clock::local_time();
i->connection = c; i->connection = c;
return true;
} }
void policy::peer_from_tracker(const address& remote, const peer_id& id) void policy::peer_from_tracker(const address& remote, const peer_id& id)
@ -291,11 +307,14 @@ namespace libtorrent
return; return;
} }
if (i->banned) return;
i->connected = boost::posix_time::second_clock::local_time(); i->connected = boost::posix_time::second_clock::local_time();
i->connection = m_torrent->connect_to_peer(remote, id); i->connection = m_torrent->connect_to_peer(remote, id);
} }
catch(network_error&) {} catch(network_error&) {}
catch(protocol_error&) {}
} }
// this is called when we are choked by a peer // this is called when we are choked by a peer

View File

@ -190,7 +190,7 @@ namespace libtorrent
{ {
listener->listen(m_listen_port, 5); listener->listen(m_listen_port, 5);
} }
catch(network_error&) catch(std::exception&)
{ {
if (m_listen_port > max_port) if (m_listen_port > max_port)
throw; throw;
@ -299,7 +299,7 @@ namespace libtorrent
// (*m_logger) << "readable: " << p->first->sender().as_string() << "\n"; // (*m_logger) << "readable: " << p->first->sender().as_string() << "\n";
p->second->receive_data(); p->second->receive_data();
} }
catch(network_error&) catch(std::exception&)
{ {
// the connection wants to disconnect for some reason, remove it // the connection wants to disconnect for some reason, remove it
// from the connection-list // from the connection-list
@ -338,7 +338,7 @@ namespace libtorrent
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n"; // (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
p->second->send_data(); p->second->send_data();
} }
catch(network_error&) catch(std::exception&)
{ {
// the connection wants to disconnect for some reason, remove it // the connection wants to disconnect for some reason, remove it
// from the connection-list // from the connection-list

View File

@ -366,6 +366,7 @@ int libtorrent::piece_file::read(char* buf, int size, bool lock_)
int read_bytes = left_to_read; int read_bytes = left_to_read;
if (m_file_offset + read_bytes > m_file_iter->size) if (m_file_offset + read_bytes > m_file_iter->size)
read_bytes = m_file_iter->size - m_file_offset; read_bytes = m_file_iter->size - m_file_offset;
assert(read_bytes > 0);
m_file.read(buf + buf_pos, read_bytes); 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; int write_bytes = left_to_write;
if (m_file_offset + write_bytes > m_file_iter->size) 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; write_bytes = m_file_iter->size - m_file_offset;
}
assert(buf_pos >= 0); assert(buf_pos >= 0);
assert(write_bytes > 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; buf_pos += write_bytes;
assert(buf_pos >= 0); assert(buf_pos >= 0);
m_file_offset += write_bytes; m_file_offset += write_bytes;
assert(m_file_offset < m_file_iter->size);
m_piece_offset += write_bytes; m_piece_offset += write_bytes;
if (left_to_write > 0) if (left_to_write > 0)
@ -522,6 +527,7 @@ void libtorrent::piece_file::write(const char* buf, int size, bool lock_)
++m_file_iter; ++m_file_iter;
assert(m_file_iter != m_storage->m_torrent_file->end_files()); 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 / boost::filesystem::path path = m_storage->m_save_path /
m_file_iter->path / m_file_iter->filename; m_file_iter->path / m_file_iter->filename;

View File

@ -240,8 +240,69 @@ namespace libtorrent
!= m_connections.end(); != 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) 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); m_picker.we_have(index);
for (std::vector<peer_connection*>::iterator i = m_connections.begin(); i != m_connections.end(); ++i) for (std::vector<peer_connection*>::iterator i = m_connections.begin(); i != m_connections.end(); ++i)
(*i)->announce_piece(index); (*i)->announce_piece(index);
@ -378,7 +439,7 @@ namespace libtorrent
= m_ses->m_connections.find(p->get_socket()); = m_ses->m_connections.find(p->get_socket());
assert(i != m_ses->m_connections.end()); 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() void torrent::close_all_connections()

View File

@ -156,6 +156,11 @@ namespace libtorrent
++i) ++i)
{ {
peer_connection* peer = *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()); v.push_back(peer_info());
peer_info& p = v.back(); peer_info& p = v.back();