📄 peer_connection_base.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 <sstream>#include <rak/error_number.h>#include "torrent/exceptions.h"#include "torrent/block.h"#include "data/chunk_iterator.h"#include "data/chunk_list.h"#include "download/choke_manager.h"#include "download/chunk_selector.h"#include "download/chunk_statistics.h"#include "download/download_info.h"#include "download/download_main.h"#include "net/socket_base.h"#include "torrent/connection_manager.h"#include "torrent/peer_info.h"#include "peer_connection_base.h"#include "manager.h"namespace torrent {PeerConnectionBase::PeerConnectionBase() : m_download(NULL), m_down(new ProtocolRead()), m_up(new ProtocolWrite()), m_peerInfo(NULL), m_downStall(0), m_sendChoked(false), m_sendInterested(false) {}PeerConnectionBase::~PeerConnectionBase() { delete m_up; delete m_down;}voidPeerConnectionBase::initialize(DownloadMain* download, PeerInfo* peerInfo, SocketFd fd, Bitfield* bitfield) { if (get_fd().is_valid()) throw internal_error("Tried to re-set PeerConnection."); if (!peerInfo->is_valid() || !fd.is_valid()) throw internal_error("PeerConnectionBase::set(...) received bad input."); set_fd(fd); m_peerInfo = peerInfo; m_download = download; m_peerChunks.set_peer_info(m_peerInfo); m_peerChunks.bitfield()->swap(*bitfield); m_peerChunks.upload_throttle()->set_list_iterator(m_download->upload_throttle()->end()); m_peerChunks.upload_throttle()->slot_activate(rak::make_mem_fun(this, &PeerConnectionBase::receive_throttle_up_activate)); m_peerChunks.download_throttle()->set_list_iterator(m_download->download_throttle()->end()); m_peerChunks.download_throttle()->slot_activate(rak::make_mem_fun(this, &PeerConnectionBase::receive_throttle_down_activate)); download_queue()->set_delegator(m_download->delegator()); download_queue()->set_peer_chunks(&m_peerChunks); manager->poll()->open(this); manager->poll()->insert_read(this); manager->poll()->insert_write(this); manager->poll()->insert_error(this); m_timeLastRead = cachedTime; m_download->chunk_statistics()->received_connect(&m_peerChunks); // Hmm... cleanup? update_interested(); initialize_custom();}voidPeerConnectionBase::cleanup() { if (!get_fd().is_valid()) return; if (m_download == NULL) throw internal_error("PeerConnection::~PeerConnection() m_fd is valid but m_state and/or m_net is NULL"); m_downloadQueue.clear(); up_chunk_release(); down_chunk_release(); m_download->choke_manager()->disconnected(this); m_download->chunk_statistics()->received_disconnect(&m_peerChunks); manager->poll()->remove_read(this); manager->poll()->remove_write(this); manager->poll()->remove_error(this); manager->poll()->close(this); manager->connection_manager()->dec_socket_count(); get_fd().close(); get_fd().clear(); m_download->upload_throttle()->erase(m_peerChunks.upload_throttle()); m_download->download_throttle()->erase(m_peerChunks.download_throttle()); m_up->set_state(ProtocolWrite::INTERNAL_ERROR); m_down->set_state(ProtocolRead::INTERNAL_ERROR); m_download = NULL;}voidPeerConnectionBase::load_up_chunk() { if (m_upChunk.is_valid() && m_upChunk.index() == m_upPiece.index()) { // Better checking needed. // m_upChunk.chunk()->preload(m_upPiece.offset(), m_upChunk.chunk()->size()); return; } up_chunk_release(); m_upChunk = m_download->chunk_list()->get(m_upPiece.index(), false); if (!m_upChunk.is_valid()) throw storage_error("File chunk read error: " + std::string(m_upChunk.error_number().c_str())); // Make sure we preload the next step once we get past the length // here. This is just some testing, don't include this with the // release. (Yet)// if (m_peerChunks.upload_throttle()->rate()->rate() >= 10 << 10)// m_upChunk.chunk()->preload(m_upPiece.offset(), m_upChunk.chunk()->size());// m_upChunk.chunk()->preload(m_upPiece.offset(), std::min(128u << 10, m_peerChunks.upload_throttle()->rate()->rate() * 10));}voidPeerConnectionBase::set_snubbed(bool v) { if (v == m_peerChunks.is_snubbed()) return; bool wasUploadWanted = is_upload_wanted(); m_peerChunks.set_snubbed(v); if (v) { if (wasUploadWanted) m_download->choke_manager()->set_not_interested(this); } else { if (is_upload_wanted()) m_download->choke_manager()->set_interested(this); }}voidPeerConnectionBase::receive_choke(bool v) { if (v == m_up->choked()) throw internal_error("PeerConnectionBase::receive_choke(...) already set to the same state."); write_insert_poll_safe(); m_sendChoked = true; m_up->set_choked(v); m_timeLastChoked = cachedTime;}voidPeerConnectionBase::receive_throttle_down_activate() { manager->poll()->insert_read(this);}voidPeerConnectionBase::receive_throttle_up_activate() { manager->poll()->insert_write(this);}voidPeerConnectionBase::event_error() { m_download->connection_list()->erase(this, 0);}boolPeerConnectionBase::down_chunk_start(const Piece& piece) { if (!download_queue()->downloading(piece)) { if (piece.length() == 0) m_download->info()->signal_network_log().emit("Received piece with length zero."); return false; } if (!m_download->content()->is_valid_piece(piece)) throw internal_error("Incoming pieces list contains a bad piece."); if (!m_downChunk.is_valid() || piece.index() != m_downChunk.index()) { down_chunk_release(); m_downChunk = m_download->chunk_list()->get(piece.index(), true); if (!m_downChunk.is_valid()) throw storage_error("File chunk write error: " + std::string(m_downChunk.error_number().c_str()) + "."); } return m_downloadQueue.transfer()->is_leader();}voidPeerConnectionBase::down_chunk_finished() { if (!download_queue()->transfer()->is_finished()) throw internal_error("PeerConnectionBase::down_chunk_finished() Transfer not finished."); if (download_queue()->transfer()->is_leader()) { if (!m_downChunk.is_valid()) throw internal_error("PeerConnectionBase::down_chunk_finished() Transfer is the leader, but no chunk allocated."); download_queue()->finished(); m_downChunk.object()->set_time_modified(cachedTime); } else { download_queue()->skipped(); } if (m_downStall > 0) m_downStall--; // TODO: clear m_down.data? // TODO: remove throttle if choked? Rarely happens though. write_insert_poll_safe();}boolPeerConnectionBase::down_chunk() { if (!m_download->download_throttle()->is_throttled(m_peerChunks.download_throttle())) throw internal_error("PeerConnectionBase::down_chunk() tried to read a piece but is not in throttle list"); if (!m_downChunk.chunk()->is_writable()) throw internal_error("PeerConnectionBase::down_part() chunk not writable, permission denided"); uint32_t quota = m_download->download_throttle()->node_quota(m_peerChunks.download_throttle()); if (quota == 0) { manager->poll()->remove_read(this); m_download->download_throttle()->node_deactivate(m_peerChunks.download_throttle()); return false; } uint32_t bytesTransfered = 0; BlockTransfer* transfer = m_downloadQueue.transfer(); Chunk::data_type data; ChunkIterator itr(m_downChunk.chunk(), transfer->piece().offset() + transfer->position(), transfer->piece().offset() + std::min(transfer->position() + quota, transfer->piece().length())); do { data = itr.data(); data.second = read_stream_throws(data.first, data.second); bytesTransfered += data.second; } while (itr.used(data.second)); transfer->adjust_position(bytesTransfered);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -