⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 block.cc

📁 LibTorrent is a BitTorrent library written in C++ for *nix, with a focus on high performance and goo
💻 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 <algorithm>#include <functional>#include <rak/functional.h>#include "block.h"#include "block_failed.h"#include "block_list.h"#include "block_transfer.h"#include "exceptions.h"namespace torrent {voidBlockTransfer::create_dummy(PeerInfo* peerInfo, const Piece& piece) {  set_peer_info(peerInfo);  m_block = NULL;  m_piece = piece;  m_state = BlockTransfer::STATE_ERASED;  m_position = 0;  m_stall = 0;  m_failedIndex = invalid_index;}Block::~Block() {  m_leader = NULL;  std::for_each(m_queued.begin(), m_queued.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));  m_queued.clear();  std::for_each(m_transfers.begin(), m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));  m_transfers.clear();  if (m_notStalled != 0)    throw internal_error("Block::clear() m_stalled != 0.");  delete m_failedList;}BlockTransfer*Block::insert(PeerInfo* peerInfo) {  if (find_queued(peerInfo) || find_transfer(peerInfo))    throw internal_error("Block::insert(...) find_queued(peerInfo) || find_transfer(peerInfo).");  m_notStalled++;  transfer_list_type::iterator itr = m_queued.insert(m_queued.end(), new BlockTransfer());  (*itr)->set_peer_info(peerInfo);  (*itr)->set_block(this);  (*itr)->set_piece(m_piece);  (*itr)->set_state(BlockTransfer::STATE_QUEUED);  (*itr)->set_position(0);  (*itr)->set_stall(0);  (*itr)->set_failed_index(BlockFailed::invalid_index);  return (*itr);}  voidBlock::erase(BlockTransfer* transfer) {  if (transfer->is_erased())    throw internal_error("Block::erase(...) transfer already erased.");  m_notStalled -= transfer->stall() == 0;  if (transfer->is_queued()) {    transfer_list_type::iterator itr = std::find(m_queued.begin(), m_queued.end(), transfer);    if (itr == m_queued.end())      throw internal_error("Block::erase(...) Could not find transfer.");    m_queued.erase(itr);  } else if (!transfer->is_finished()) {    transfer_list_type::iterator itr = std::find(m_transfers.begin(), m_transfers.end(), transfer);    if (itr == m_transfers.end())      throw internal_error("Block::erase(...) Could not find transfer.");    // Need to do something different here for now, i think.    m_transfers.erase(itr);    if (transfer == m_leader) {      // When the leader is erased then any non-leading transfer must      // be promoted. These non-leading transfers are guaranteed to      // have the same data up to their position. PeerConnectionBase      // assumes that a Block with non-leaders have a leader.      // Create a range containing transfers with      // is_not_leader(). Erased transfer will end up in the back.      transfer_list_type::iterator first = std::find_if(m_transfers.begin(), m_transfers.end(), std::not1(std::mem_fun(&BlockTransfer::is_leader)));      transfer_list_type::iterator last = std::stable_partition(first, m_transfers.end(), std::mem_fun(&BlockTransfer::is_not_leader));      transfer_list_type::iterator newLeader = std::max_element(first, last, rak::less2(std::mem_fun(&BlockTransfer::position), std::mem_fun(&BlockTransfer::position)));      if (newLeader != last) {        m_leader = *newLeader;        m_leader->set_state(BlockTransfer::STATE_LEADER);      } else {        m_leader = NULL;        // If we have no new leader, remove the erased (dissimilar)        // transfers so they can get another shot. They cannot be        // removed when found dissimilar as that would result in them        // being queued immediately.        remove_erased_transfers();      }    }  } else {    throw internal_error("Block::erase(...) Transfer is finished.");  }  transfer->set_block(NULL);  delete transfer;}boolBlock::transfering(BlockTransfer* transfer) {  if (!transfer->is_valid())    throw internal_error("Block::transfering(...) transfer->block() == NULL.");  transfer_list_type::iterator itr = std::find(m_queued.begin(), m_queued.end(), transfer);  if (itr == m_queued.end())    throw internal_error("Block::transfering(...) not queued.");  m_queued.erase(itr);  m_transfers.insert(m_transfers.end(), transfer);  // If this block already has an active transfer, make this transfer  // skip the piece. If this transfer gets ahead of the currently  // transfering, it will (a) take over as the leader if the data is  // the same or (b) erase itself from this block if the data does not  // match.  if (m_leader != NULL) {    transfer->set_state(BlockTransfer::STATE_NOT_LEADER);    return false;  } else {    m_leader = transfer;    transfer->set_state(BlockTransfer::STATE_LEADER);    return true;  }}boolBlock::completed(BlockTransfer* transfer) {  if (!transfer->is_valid())    throw internal_error("Block::completed(...) transfer->block() == NULL.");  if (!transfer->is_leader())    throw internal_error("Block::completed(...) transfer is not the leader.");  // Special case where another ignored transfer finished before the  // leader?  //  // Perhaps do magic to the transfer, erase it or something.  if (!is_finished())    throw internal_error("Block::completed(...) !is_finished().");  if (transfer != m_leader)    throw internal_error("Block::completed(...) transfer != m_leader.");  m_parent->inc_finished();  if ((Block::size_type)std::count_if(m_parent->begin(), m_parent->end(), std::mem_fun_ref(&Block::is_finished)) < m_parent->finished())    throw internal_error("Block::completed(...) Finished blocks too large.");  m_notStalled -= transfer->stall() == 0;  transfer->set_block(NULL);  transfer->set_stall(~uint32_t());  // Currently just throw out the queued transfers. In case the hash  // check fails, we might consider telling pcb during the call to  // Block::transfering(...). But that would propably not be correct  // as we want to trigger cancel messages from here, as hash fail is  // a rare occurrence.  std::for_each(m_queued.begin(), m_queued.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));  m_queued.clear();  // We need to invalidate those unfinished and keep the one that  // finished for later reference.  remove_non_leader_transfers();    if (m_transfers.empty() || m_transfers.back() != transfer)    throw internal_error("Block::completed(...) m_transfers.empty() || m_transfers.back() != transfer.");  return m_parent->is_all_finished();}// Mark a non-leading transfer as having received dissimilar data to// the leader. It is then marked as erased so that we know its data// was not used, yet keep it in m_transfers so as not to cause a// re-download.voidBlock::transfer_dissimilar(BlockTransfer* transfer) {  if (!transfer->is_not_leader() || m_leader == transfer)    throw internal_error("Block::transfer_dissimilar(...) transfer is the leader.");  m_notStalled -= transfer->stall() == 0;  // Why not just delete? Gets done by completed(), though when  // erasing the leader we need to remove dissimilar unless we have  // another leader.    transfer->set_state(BlockTransfer::STATE_ERASED);  transfer->set_position(0);  transfer->set_block(NULL);}voidBlock::stalled_transfer(BlockTransfer* transfer) {  if (transfer->stall() == 0) {    if (m_notStalled == 0)      throw internal_error("Block::stalled(...) m_notStalled == 0.");    m_notStalled--;    // Do magic here.  }  transfer->set_stall(transfer->stall() + 1);}voidBlock::change_leader(BlockTransfer* transfer) {  if (m_leader == transfer)    throw internal_error("Block::change_leader(...) m_leader == transfer.");  if (is_finished())    throw internal_error("Block::change_leader(...) is_finished().");  if (m_leader != NULL)    m_leader->set_state(BlockTransfer::STATE_NOT_LEADER);  m_leader = transfer;  m_leader->set_state(BlockTransfer::STATE_LEADER);}voidBlock::failed_leader() {  if (!is_finished())    throw internal_error("Block::failed_leader(...) !is_finished().");  m_leader = NULL;  if (m_failedList != NULL)    m_failedList->set_current(BlockFailed::invalid_index);}inline voidBlock::invalidate_transfer(BlockTransfer* transfer) {  if (transfer == m_leader)    throw internal_error("Block::invalidate_transfer(...) transfer == m_leader.");  // FIXME: Various other accounting like position and counters.  if (!transfer->is_valid()) {    delete transfer;  } else {    m_notStalled -= transfer->stall() == 0;    transfer->set_block(NULL);  }}voidBlock::remove_erased_transfers() {  transfer_list_type::iterator split = std::stable_partition(m_transfers.begin(), m_transfers.end(), std::not1(std::mem_fun(&BlockTransfer::is_erased)));  std::for_each(split, m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));  m_transfers.erase(split, m_transfers.end());}voidBlock::remove_non_leader_transfers() {  transfer_list_type::iterator split = std::stable_partition(m_transfers.begin(), m_transfers.end(), std::mem_fun(&BlockTransfer::is_leader));  std::for_each(split, m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));  m_transfers.erase(split, m_transfers.end());}BlockTransfer*Block::find_queued(const PeerInfo* p) {  transfer_list_type::iterator itr = std::find_if(m_queued.begin(), m_queued.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));  if (itr == m_queued.end())    return NULL;  else    return *itr;}const BlockTransfer*Block::find_queued(const PeerInfo* p) const {  transfer_list_type::const_iterator itr = std::find_if(m_queued.begin(), m_queued.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));  if (itr == m_queued.end())    return NULL;  else    return *itr;}BlockTransfer*Block::find_transfer(const PeerInfo* p) {  transfer_list_type::iterator itr = std::find_if(m_transfers.begin(), m_transfers.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));  if (itr == m_transfers.end())    return NULL;  else    return *itr;}const BlockTransfer*Block::find_transfer(const PeerInfo* p) const {  transfer_list_type::const_iterator itr = std::find_if(m_transfers.begin(), m_transfers.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));  if (itr == m_transfers.end())    return NULL;  else    return *itr;}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -