📄 peer_connection_leech.cc
字号:
// libTorrent - BitTorrent library// Copyright (C) 2005-2006, Jari Sundell//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.// // This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// // You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//// In addition, as a special exception, the copyright holders give// permission to link the code of portions of this program with the// OpenSSL library under certain conditions as described in each// individual source file, and distribute linked combinations// including the two.//// You must obey the GNU General Public License in all respects for// all of the code used other than OpenSSL. If you modify file(s)// with this exception, you may extend this exception to your version// of the file(s), but you are not obligated to do so. If you do not// wish to do so, delete this exception statement from your version.// If you delete this exception statement from all source files in the// program, then also delete it here.//// Contact: Jari Sundell <jaris@ifi.uio.no>//// Skomakerveien 33// 3185 Skoppum, NORWAY#include "config.h"#include <cstring>#include <sstream>#include "data/content.h"#include "data/chunk_list_node.h"#include "download/chunk_selector.h"#include "download/chunk_statistics.h"#include "download/download_info.h"#include "download/download_main.h"#include "peer_connection_leech.h"namespace torrent {PeerConnectionLeech::~PeerConnectionLeech() {// if (m_download != NULL && m_down->get_state() != ProtocolRead::READ_BITFIELD)// m_download->bitfield_counter().dec(m_peerChunks.bitfield()->bitfield());// priority_queue_erase(&taskScheduler, &m_taskSendChoke);}voidPeerConnectionLeech::initialize_custom() {// if (m_download->content()->chunks_completed() != 0) {// m_up->write_bitfield(m_download->content()->bitfield()->size_bytes());// m_up->buffer()->prepare_end();// m_up->set_position(0);// m_up->set_state(ProtocolWrite::WRITE_BITFIELD_HEADER);// }}voidPeerConnectionLeech::update_interested() {// FIXME: if (m_download->delegator()->get_select().interested(m_peerChunks.bitfield()->bitfield())) { // Consider just setting to interested without checking the // bitfield. The status might change by the time we get unchoked // anyway. if (true) { m_sendInterested = !m_up->interested(); m_up->set_interested(true); } else { m_sendInterested = m_up->interested(); m_up->set_interested(false); } m_peerChunks.download_cache()->clear();}// Disconnecting connections where both are seeders should be done by// DownloadMain when it finishes the last chunk.voidPeerConnectionLeech::receive_finished_chunk(int32_t index) { m_peerChunks.have_queue()->push_back(index); if (download_queue()->has_index(index)) throw internal_error("PeerConnection::sendHave(...) found a request with the same index");}boolPeerConnectionLeech::receive_keepalive() { if (cachedTime - m_timeLastRead > rak::timer::from_seconds(240)) return false; // There's no point in adding ourselves to the write poll if the // buffer is full, as that will already have been taken care of. if (m_up->get_state() == ProtocolWrite::IDLE && m_up->can_write_keepalive()) { write_insert_poll_safe(); m_up->write_keepalive(); } m_tryRequest = true; // Stall pieces when more than one receive_keepalive() has been // called while a single piece is downloading. // // m_downStall is decremented for every successfull download, so it // should stay at zero or one when downloading at an acceptable // speed. Thus only when m_downStall >= 2 is the download actually // stalling. if (!download_queue()->empty() && m_downStall++ != 0) download_queue()->stall(); return true;}// We keep the message in the buffer if it is incomplete instead of// keeping the state and remembering the read information. This// shouldn't happen very often compared to full reads.inline boolPeerConnectionLeech::read_message() { ProtocolBuffer<512>* buf = m_down->buffer(); if (buf->remaining() < 4) return false; // Remember the start of the message so we may reset it if we don't // have the whole message. ProtocolBuffer<512>::iterator beginning = buf->position(); uint32_t length = buf->read_32(); if (length == 0) { // Keepalive message. m_down->set_last_command(ProtocolBase::KEEP_ALIVE); return true; } else if (buf->remaining() < 1) { buf->set_position_itr(beginning); return false; } else if (length > (1 << 20)) { throw network_error("PeerConnectionLeech::read_message() got an invalid message length."); } // We do not verify the message length of those with static // length. A bug in the remote client causing the message start to // be unsyncronized would in practically all cases be caught with // the above test. // // Those that do in some weird way manage to produce a valid // command, will not be able to do any damage as malicious // peer. Those cases should be caught elsewhere in the code. // Temporary. m_down->set_last_command((ProtocolBase::Protocol)buf->peek_8()); switch (buf->read_8()) { case ProtocolBase::CHOKE: m_down->set_choked(true); m_peerChunks.download_cache()->disable(); download_queue()->cancel(); m_download->download_throttle()->erase(m_peerChunks.download_throttle()); return true; case ProtocolBase::UNCHOKE: if (is_down_choked()) { write_insert_poll_safe(); m_down->set_choked(false); m_tryRequest = true; } return true; case ProtocolBase::INTERESTED: set_remote_interested(); return true; case ProtocolBase::NOT_INTERESTED: set_remote_not_interested(); return true; case ProtocolBase::HAVE: if (!m_down->can_read_have_body()) break; read_have_chunk(buf->read_32()); return true; case ProtocolBase::REQUEST: if (!m_down->can_read_request_body()) break; if (!m_up->choked()) { write_insert_poll_safe(); read_request_piece(m_down->read_request()); } else { m_down->read_request(); } return true; case ProtocolBase::PIECE: if (!m_down->can_read_piece_body()) break; if (!down_chunk_start(m_down->read_piece(length - 9))) { // We don't want this chunk. if (down_chunk_skip_from_buffer()) { m_tryRequest = true; down_chunk_finished(); return true; } else { m_down->set_state(ProtocolRead::READ_SKIP_PIECE); return false; } } else { if (down_chunk_from_buffer()) { m_tryRequest = true; down_chunk_finished(); return true; } else { m_down->set_state(ProtocolRead::READ_PIECE); m_download->download_throttle()->insert(m_peerChunks.download_throttle()); return false; } } case ProtocolBase::CANCEL: if (!m_down->can_read_cancel_body()) break; read_cancel_piece(m_down->read_request()); return true; default: throw network_error("Received unsupported message type."); } // We were unsuccessfull in reading the message, need more data. buf->set_position_itr(beginning); return false;}voidPeerConnectionLeech::event_read() { m_timeLastRead = cachedTime; // Need to make sure ProtocolBuffer::end() is pointing to the end of // the unread data, and that the unread data starts from the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -