1
// libTorrent - BitTorrent library
2
// Copyright (C) 2005-2006, Jari Sundell
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
// In addition, as a special exception, the copyright holders give
19
// permission to link the code of portions of this program with the
20
// OpenSSL library under certain conditions as described in each
21
// individual source file, and distribute linked combinations
24
// You must obey the GNU General Public License in all respects for
25
// all of the code used other than OpenSSL. If you modify file(s)
26
// with this exception, you may extend this exception to your version
27
// of the file(s), but you are not obligated to do so. If you do not
28
// wish to do so, delete this exception statement from your version.
29
// If you delete this exception statement from all source files in the
30
// program, then also delete it here.
32
// Contact: Jari Sundell <jaris@ifi.uio.no>
35
// 3185 Skoppum, NORWAY
41
#include <rak/functional.h>
43
#include "peer/peer_info.h"
44
#include "protocol/peer_connection_base.h"
47
#include "block_failed.h"
48
#include "block_list.h"
49
#include "block_transfer.h"
50
#include "exceptions.h"
57
std::for_each(m_queued.begin(), m_queued.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));
60
std::for_each(m_transfers.begin(), m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));
63
if (m_notStalled != 0)
64
throw internal_error("Block::clear() m_stalled != 0.");
70
Block::insert(PeerInfo* peerInfo) {
71
if (find_queued(peerInfo) || find_transfer(peerInfo))
72
throw internal_error("Block::insert(...) find_queued(peerInfo) || find_transfer(peerInfo).");
76
transfer_list_type::iterator itr = m_queued.insert(m_queued.end(), new BlockTransfer());
78
(*itr)->set_peer_info(peerInfo);
79
(*itr)->set_block(this);
80
(*itr)->set_piece(m_piece);
81
(*itr)->set_state(BlockTransfer::STATE_QUEUED);
82
(*itr)->set_position(0);
84
(*itr)->set_failed_index(BlockFailed::invalid_index);
86
peerInfo->set_transfer_counter(peerInfo->transfer_counter() + 1);
92
Block::erase(BlockTransfer* transfer) {
93
if (transfer->is_erased())
94
throw internal_error("Block::erase(...) transfer already erased.");
96
m_notStalled -= transfer->stall() == 0;
98
if (transfer->is_queued()) {
99
transfer_list_type::iterator itr = std::find(m_queued.begin(), m_queued.end(), transfer);
101
if (itr == m_queued.end())
102
throw internal_error("Block::erase(...) Could not find transfer.");
106
} else if (!transfer->is_finished()) {
107
transfer_list_type::iterator itr = std::find(m_transfers.begin(), m_transfers.end(), transfer);
109
if (itr == m_transfers.end())
110
throw internal_error("Block::erase(...) Could not find transfer.");
112
// Need to do something different here for now, i think.
113
m_transfers.erase(itr);
115
if (transfer == m_leader) {
117
// When the leader is erased then any non-leading transfer must
118
// be promoted. These non-leading transfers are guaranteed to
119
// have the same data up to their position. PeerConnectionBase
120
// assumes that a Block with non-leaders have a leader.
122
// Create a range containing transfers with
123
// is_not_leader(). Erased transfer will end up in the back.
125
transfer_list_type::iterator first = std::find_if(m_transfers.begin(), m_transfers.end(), std::not1(std::mem_fun(&BlockTransfer::is_leader)));
126
transfer_list_type::iterator last = std::stable_partition(first, m_transfers.end(), std::mem_fun(&BlockTransfer::is_not_leader));
128
transfer_list_type::iterator newLeader = std::max_element(first, last, rak::less2(std::mem_fun(&BlockTransfer::position), std::mem_fun(&BlockTransfer::position)));
130
if (newLeader != last) {
131
m_leader = *newLeader;
132
m_leader->set_state(BlockTransfer::STATE_LEADER);
136
// If we have no new leader, remove the erased (dissimilar)
137
// transfers so they can get another shot. They cannot be
138
// removed when found dissimilar as that would result in them
139
// being queued immediately.
140
remove_erased_transfers();
145
throw internal_error("Block::erase(...) Transfer is finished.");
148
if (transfer->peer_info() != NULL)
149
transfer->peer_info()->set_transfer_counter(transfer->peer_info()->transfer_counter() - 1);
151
transfer->set_block(NULL);
156
Block::transfering(BlockTransfer* transfer) {
157
if (!transfer->is_valid())
158
throw internal_error("Block::transfering(...) transfer->block() == NULL.");
160
transfer_list_type::iterator itr = std::find(m_queued.begin(), m_queued.end(), transfer);
162
if (itr == m_queued.end())
163
throw internal_error("Block::transfering(...) not queued.");
166
m_transfers.insert(m_transfers.end(), transfer);
168
// If this block already has an active transfer, make this transfer
169
// skip the piece. If this transfer gets ahead of the currently
170
// transfering, it will (a) take over as the leader if the data is
171
// the same or (b) erase itself from this block if the data does not
173
if (m_leader != NULL) {
174
transfer->set_state(BlockTransfer::STATE_NOT_LEADER);
180
transfer->set_state(BlockTransfer::STATE_LEADER);
186
Block::completed(BlockTransfer* transfer) {
187
if (!transfer->is_valid())
188
throw internal_error("Block::completed(...) transfer->block() == NULL.");
190
if (!transfer->is_leader())
191
throw internal_error("Block::completed(...) transfer is not the leader.");
193
// Special case where another ignored transfer finished before the
196
// Perhaps do magic to the transfer, erase it or something.
198
throw internal_error("Block::completed(...) !is_finished().");
200
if (transfer != m_leader)
201
throw internal_error("Block::completed(...) transfer != m_leader.");
203
m_parent->inc_finished();
205
if ((Block::size_type)std::count_if(m_parent->begin(), m_parent->end(), std::mem_fun_ref(&Block::is_finished)) < m_parent->finished())
206
throw internal_error("Block::completed(...) Finished blocks too large.");
208
m_notStalled -= transfer->stall() == 0;
210
transfer->set_block(NULL);
211
transfer->set_stall(~uint32_t());
213
// Currently just throw out the queued transfers. In case the hash
214
// check fails, we might consider telling pcb during the call to
215
// Block::transfering(...). But that would propably not be correct
216
// as we want to trigger cancel messages from here, as hash fail is
217
// a rare occurrence.
218
std::for_each(m_queued.begin(), m_queued.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));
221
// We need to invalidate those unfinished and keep the one that
222
// finished for later reference.
223
remove_non_leader_transfers();
225
if (m_transfers.empty() || m_transfers.back() != transfer)
226
throw internal_error("Block::completed(...) m_transfers.empty() || m_transfers.back() != transfer.");
228
return m_parent->is_all_finished();
231
// Mark a non-leading transfer as having received dissimilar data to
232
// the leader. It is then marked as erased so that we know its data
233
// was not used, yet keep it in m_transfers so as not to cause a
236
Block::transfer_dissimilar(BlockTransfer* transfer) {
237
if (!transfer->is_not_leader() || m_leader == transfer)
238
throw internal_error("Block::transfer_dissimilar(...) transfer is the leader.");
240
m_notStalled -= transfer->stall() == 0;
242
// Why not just delete? Gets done by completed(), though when
243
// erasing the leader we need to remove dissimilar unless we have
246
transfer->set_state(BlockTransfer::STATE_ERASED);
247
transfer->set_position(0);
248
transfer->set_block(NULL);
252
Block::stalled_transfer(BlockTransfer* transfer) {
253
if (transfer->stall() == 0) {
254
if (m_notStalled == 0)
255
throw internal_error("Block::stalled(...) m_notStalled == 0.");
262
transfer->set_stall(transfer->stall() + 1);
266
Block::change_leader(BlockTransfer* transfer) {
267
if (m_leader == transfer)
268
throw internal_error("Block::change_leader(...) m_leader == transfer.");
271
throw internal_error("Block::change_leader(...) is_finished().");
273
if (m_leader != NULL)
274
m_leader->set_state(BlockTransfer::STATE_NOT_LEADER);
277
m_leader->set_state(BlockTransfer::STATE_LEADER);
281
Block::failed_leader() {
283
throw internal_error("Block::failed_leader(...) !is_finished().");
287
if (m_failedList != NULL)
288
m_failedList->set_current(BlockFailed::invalid_index);
292
Block::create_dummy(BlockTransfer* transfer, PeerInfo* peerInfo, const Piece& piece) {
293
transfer->set_peer_info(peerInfo);
295
if (peerInfo != NULL)
296
peerInfo->set_transfer_counter(peerInfo->transfer_counter() + 1);
298
transfer->set_block(NULL);
299
transfer->set_piece(piece);
300
transfer->set_state(BlockTransfer::STATE_ERASED);
302
transfer->set_position(0);
303
transfer->set_stall(0);
304
transfer->set_failed_index(BlockTransfer::invalid_index);
308
Block::release(BlockTransfer* transfer) {
309
if (!transfer->is_valid()) {
310
if (transfer->peer_info() != NULL)
311
transfer->peer_info()->set_transfer_counter(transfer->peer_info()->transfer_counter() - 1);
315
transfer->block()->erase(transfer);
320
Block::invalidate_transfer(BlockTransfer* transfer) {
321
if (transfer == m_leader)
322
throw internal_error("Block::invalidate_transfer(...) transfer == m_leader.");
324
// FIXME: Various other accounting like position and counters.
325
if (!transfer->is_valid()) {
326
if (transfer->peer_info() != NULL)
327
transfer->peer_info()->set_transfer_counter(transfer->peer_info()->transfer_counter() - 1);
332
m_notStalled -= transfer->stall() == 0;
334
transfer->set_block(NULL);
336
// Do the canceling magic here.
337
if (transfer->peer_info()->connection() != NULL)
338
transfer->peer_info()->connection()->cancel_transfer(transfer);
343
Block::remove_erased_transfers() {
344
transfer_list_type::iterator split = std::stable_partition(m_transfers.begin(), m_transfers.end(), std::not1(std::mem_fun(&BlockTransfer::is_erased)));
346
std::for_each(split, m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));
347
m_transfers.erase(split, m_transfers.end());
351
Block::remove_non_leader_transfers() {
352
transfer_list_type::iterator split = std::stable_partition(m_transfers.begin(), m_transfers.end(), std::mem_fun(&BlockTransfer::is_leader));
354
std::for_each(split, m_transfers.end(), std::bind1st(std::mem_fun(&Block::invalidate_transfer), this));
355
m_transfers.erase(split, m_transfers.end());
359
Block::find_queued(const PeerInfo* p) {
360
transfer_list_type::iterator itr = std::find_if(m_queued.begin(), m_queued.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));
362
if (itr == m_queued.end())
369
Block::find_queued(const PeerInfo* p) const {
370
transfer_list_type::const_iterator itr = std::find_if(m_queued.begin(), m_queued.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));
372
if (itr == m_queued.end())
379
Block::find_transfer(const PeerInfo* p) {
380
transfer_list_type::iterator itr = std::find_if(m_transfers.begin(), m_transfers.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));
382
if (itr == m_transfers.end())
389
Block::find_transfer(const PeerInfo* p) const {
390
transfer_list_type::const_iterator itr = std::find_if(m_transfers.begin(), m_transfers.end(), rak::equal(p, std::mem_fun(&BlockTransfer::peer_info)));
392
if (itr == m_transfers.end())