1
// libTorrent - BitTorrent library
2
// Copyright (C) 2005-2007, 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
42
#include "data/chunk_list.h"
43
#include "protocol/extensions.h"
44
#include "protocol/handshake_manager.h"
45
#include "protocol/initial_seed.h"
46
#include "protocol/peer_connection_base.h"
47
#include "protocol/peer_factory.h"
48
#include "tracker/tracker_manager.h"
49
#include "torrent/download.h"
50
#include "torrent/exceptions.h"
51
#include "torrent/throttle.h"
52
#include "torrent/data/file_list.h"
53
#include "torrent/peer/connection_list.h"
54
#include "torrent/peer/peer.h"
55
#include "torrent/peer/peer_info.h"
57
#include "available_list.h"
58
#include "choke_manager.h"
59
#include "chunk_selector.h"
60
#include "chunk_statistics.h"
61
#include "download_main.h"
62
#include "download_manager.h"
63
#include "download_wrapper.h"
67
DownloadInfo::DownloadInfo() :
68
m_flags(flag_compact | flag_accepting_new_peers | flag_pex_enabled | flag_pex_active),
74
m_uploadedBaseline(0),
75
m_completedBaseline(0),
81
m_loadDate(rak::timer::current_seconds()) {
84
DownloadMain::DownloadMain() :
85
m_info(new DownloadInfo),
87
m_trackerManager(new TrackerManager()),
88
m_chunkList(new ChunkList),
89
m_chunkSelector(new ChunkSelector),
90
m_chunkStatistics(new ChunkStatistics),
92
m_initialSeeding(NULL),
93
m_uploadThrottle(NULL),
94
m_downloadThrottle(NULL) {
96
m_connectionList = new ConnectionList(this);
97
m_uploadChokeManager = new ChokeManager(m_connectionList);
98
m_downloadChokeManager = new ChokeManager(m_connectionList, ChokeManager::flag_unchoke_all_new);
100
m_uploadChokeManager->set_slot_choke_weight(&calculate_upload_choke);
101
m_uploadChokeManager->set_slot_unchoke_weight(&calculate_upload_unchoke);
102
m_uploadChokeManager->set_slot_connection(std::mem_fun(&PeerConnectionBase::receive_upload_choke));
104
std::memcpy(m_uploadChokeManager->choke_weight(), weights_upload_choke, ChokeManager::weight_size_bytes);
105
std::memcpy(m_uploadChokeManager->unchoke_weight(), weights_upload_unchoke, ChokeManager::weight_size_bytes);
107
m_downloadChokeManager->set_slot_choke_weight(&calculate_download_choke);
108
m_downloadChokeManager->set_slot_unchoke_weight(&calculate_download_unchoke);
109
m_downloadChokeManager->set_slot_connection(std::mem_fun(&PeerConnectionBase::receive_download_choke));
111
std::memcpy(m_downloadChokeManager->choke_weight(), weights_download_choke, ChokeManager::weight_size_bytes);
112
std::memcpy(m_downloadChokeManager->unchoke_weight(), weights_download_unchoke, ChokeManager::weight_size_bytes);
114
m_delegator.slot_chunk_find(rak::make_mem_fun(m_chunkSelector, &ChunkSelector::find));
115
m_delegator.slot_chunk_size(rak::make_mem_fun(file_list(), &FileList::chunk_index_size));
117
m_delegator.transfer_list()->slot_canceled(std::bind1st(std::mem_fun(&ChunkSelector::not_using_index), m_chunkSelector));
118
m_delegator.transfer_list()->slot_queued(std::bind1st(std::mem_fun(&ChunkSelector::using_index), m_chunkSelector));
119
m_delegator.transfer_list()->slot_completed(std::bind1st(std::mem_fun(&DownloadMain::receive_chunk_done), this));
120
m_delegator.transfer_list()->slot_corrupt(std::bind1st(std::mem_fun(&DownloadMain::receive_corrupt_chunk), this));
122
m_delayDisconnectPeers.set_slot(rak::mem_fn(m_connectionList, &ConnectionList::disconnect_queued));
123
m_taskTrackerRequest.set_slot(rak::mem_fn(this, &DownloadMain::receive_tracker_request));
125
m_chunkList->slot_create_chunk(rak::make_mem_fun(file_list(), &FileList::create_chunk_index));
126
m_chunkList->slot_free_diskspace(rak::make_mem_fun(file_list(), &FileList::free_diskspace));
129
DownloadMain::~DownloadMain() {
130
if (m_taskTrackerRequest.is_queued())
131
throw internal_error("DownloadMain::~DownloadMain(): m_taskTrackerRequest is queued.");
134
m_connectionList->clear();
136
if (m_info->size_pex() != 0)
137
throw internal_error("DownloadMain::~DownloadMain(): m_info->size_pex() != 0.");
139
delete m_trackerManager;
140
delete m_uploadChokeManager;
141
delete m_downloadChokeManager;
142
delete m_connectionList;
144
delete m_chunkStatistics;
146
delete m_chunkSelector;
149
m_ut_pex_delta.clear();
150
m_ut_pex_initial.clear();
153
std::pair<ThrottleList*, ThrottleList*>
154
DownloadMain::throttles(const sockaddr* sa) {
155
ThrottlePair pair = ThrottlePair(NULL, NULL);
157
if (!manager->connection_manager()->address_throttle().empty())
158
pair = manager->connection_manager()->address_throttle()(sa);
160
return std::make_pair(pair.first == NULL ? upload_throttle() : pair.first->throttle_list(),
161
pair.second == NULL ? download_throttle() : pair.second->throttle_list());
165
DownloadMain::open(int flags) {
166
if (info()->is_open())
167
throw internal_error("Tried to open a download that is already open");
169
file_list()->open(flags & FileList::open_no_create);
171
m_chunkList->resize(file_list()->size_chunks());
172
m_chunkStatistics->initialize(file_list()->size_chunks());
174
info()->set_flags(DownloadInfo::flag_open);
178
DownloadMain::close() {
179
if (info()->is_active())
180
throw internal_error("Tried to close an active download");
182
if (!info()->is_open())
185
info()->unset_flags(DownloadInfo::flag_open);
187
// Don't close the tracker manager here else it will cause STOPPED
188
// requests to be lost. TODO: Check that this is valid.
189
// m_trackerManager->close();
191
m_delegator.transfer_list()->clear();
193
file_list()->mutable_bitfield()->unallocate();
194
file_list()->close();
196
// Clear the chunklist last as it requires all referenced chunks to
198
m_chunkStatistics->clear();
199
m_chunkList->clear();
200
m_chunkSelector->cleanup();
203
void DownloadMain::start() {
204
if (!info()->is_open())
205
throw internal_error("Tried to start a closed download");
207
if (info()->is_active())
208
throw internal_error("Tried to start an active download");
210
info()->set_flags(DownloadInfo::flag_active);
211
m_lastConnectedSize = 0;
213
m_delegator.set_aggressive(false);
216
receive_connect_peers();
220
DownloadMain::stop() {
221
if (!info()->is_active())
224
// Set this early so functions like receive_connect_peers() knows
225
// not to eat available peers.
226
info()->unset_flags(DownloadInfo::flag_active);
228
m_slotStopHandshakes(this);
229
connection_list()->erase_remaining(connection_list()->begin(), ConnectionList::disconnect_available);
231
delete m_initialSeeding;
232
m_initialSeeding = NULL;
234
priority_queue_erase(&taskScheduler, &m_delayDisconnectPeers);
235
priority_queue_erase(&taskScheduler, &m_taskTrackerRequest);
239
DownloadMain::start_initial_seeding() {
240
if (!file_list()->is_done())
243
m_initialSeeding = new InitialSeeding(this);
248
DownloadMain::initial_seeding_done(PeerConnectionBase* pcb) {
249
if (m_initialSeeding == NULL)
250
throw internal_error("DownloadMain::initial_seeding_done called when not initial seeding.");
252
// Close all connections but the currently active one (pcb).
253
// That one will be closed by throw close_connection() later.
254
if (m_connectionList->size() > 1) {
255
ConnectionList::iterator itr = std::find(m_connectionList->begin(), m_connectionList->end(), pcb);
256
if (itr == m_connectionList->end())
257
throw internal_error("DownloadMain::initial_seeding_done could not find current connection.");
259
std::iter_swap(m_connectionList->begin(), itr);
260
m_connectionList->erase_remaining(m_connectionList->begin() + 1, ConnectionList::disconnect_available);
263
// Switch to normal seeding.
264
DownloadManager::iterator itr = manager->download_manager()->find(m_info);
265
(*itr)->set_connection_type(Download::CONNECTION_SEED);
266
m_connectionList->slot_new_connection(&createPeerConnectionSeed);
267
delete m_initialSeeding;
268
m_initialSeeding = NULL;
270
// And close the current connection.
271
throw close_connection();
275
DownloadMain::update_endgame() {
276
if (!m_delegator.get_aggressive() &&
277
file_list()->completed_chunks() + m_delegator.transfer_list()->size() + 5 >= file_list()->size_chunks())
278
m_delegator.set_aggressive(true);
282
DownloadMain::receive_chunk_done(unsigned int index) {
283
ChunkHandle handle = m_chunkList->get(index, false);
285
if (!handle.is_valid())
286
throw storage_error("DownloadState::chunk_done(...) called with an index we couldn't retrieve from storage");
288
m_slotHashCheckAdd(handle);
292
DownloadMain::receive_corrupt_chunk(PeerInfo* peerInfo) {
293
peerInfo->set_failed_counter(peerInfo->failed_counter() + 1);
295
// Just use some very primitive heuristics here to decide if we're
296
// going to disconnect the peer. Also, consider adding a flag so we
297
// don't recalculate these things whenever the peer reconnects.
299
// That is... non at all ;)
301
if (peerInfo->failed_counter() > HandshakeManager::max_failed)
302
connection_list()->erase(peerInfo, ConnectionList::disconnect_unwanted);
306
DownloadMain::add_peer(const rak::socket_address& sa) {
307
m_slotStartHandshake(sa, this);
311
DownloadMain::receive_connect_peers() {
312
if (!info()->is_active())
315
// TODO: Is this actually going to be used?
316
AddressList* alist = peer_list()->available_list()->buffer();
318
if (!alist->empty()) {
320
peer_list()->insert_available(alist);
324
while (!peer_list()->available_list()->empty() &&
325
manager->connection_manager()->can_connect() &&
326
connection_list()->size() < connection_list()->min_size() &&
327
connection_list()->size() + m_slotCountHandshakes(this) < connection_list()->max_size()) {
328
rak::socket_address sa = peer_list()->available_list()->pop_random();
330
if (connection_list()->find(sa.c_sockaddr()) == connection_list()->end())
331
m_slotStartHandshake(sa, this);
336
DownloadMain::receive_tracker_success() {
337
if (!info()->is_active())
340
priority_queue_erase(&taskScheduler, &m_taskTrackerRequest);
341
priority_queue_insert(&taskScheduler, &m_taskTrackerRequest, (cachedTime + rak::timer::from_seconds(30)).round_seconds());
345
DownloadMain::receive_tracker_request() {
346
if (connection_list()->size() >= connection_list()->min_size())
349
if (m_info->is_pex_enabled() || connection_list()->size() < m_lastConnectedSize + 10)
350
m_trackerManager->request_next();
351
else if (!m_trackerManager->request_current())
352
m_trackerManager->request_next();
354
m_lastConnectedSize = connection_list()->size();
357
struct SocketAddressCompact_less {
358
bool operator () (const SocketAddressCompact& a, const SocketAddressCompact& b) const {
359
return (a.addr < b.addr) || ((a.addr == b.addr) && (a.port < b.port));
364
DownloadMain::do_peer_exchange() {
365
if (!info()->is_active())
366
throw internal_error("DownloadMain::do_peer_exchange called on inactive download.");
368
// Check whether we should tell the peers to stop/start sending PEX
372
if (!m_info->is_pex_active() &&
373
m_connectionList->size() < m_connectionList->min_size() / 2 &&
374
m_peerList.available_list()->size() < m_peerList.available_list()->max_size() / 4) {
375
m_info->set_flags(DownloadInfo::flag_pex_active);
377
// Only set PEX_ENABLE if we don't have max_size_pex set to zero.
378
if (m_info->size_pex() < m_info->max_size_pex())
379
togglePex = PeerConnectionBase::PEX_ENABLE;
381
} else if (m_info->is_pex_active() &&
382
m_connectionList->size() >= m_connectionList->min_size()) {
383
// m_peerList.available_list()->size() >= m_peerList.available_list()->max_size() / 2) {
384
togglePex = PeerConnectionBase::PEX_DISABLE;
385
m_info->unset_flags(DownloadInfo::flag_pex_active);
388
// Return if we don't really want to do anything?
390
ProtocolExtension::PEXList current;
392
for (ConnectionList::iterator itr = m_connectionList->begin(); itr != m_connectionList->end(); ++itr) {
393
PeerConnectionBase* pcb = (*itr)->m_ptr();
394
const rak::socket_address* sa = rak::socket_address::cast_from(pcb->peer_info()->socket_address());
396
if (pcb->peer_info()->listen_port() != 0 && sa->family() == rak::socket_address::af_inet)
397
current.push_back(SocketAddressCompact(sa->sa_inet()->address_n(), pcb->peer_info()->listen_port()));
399
if (!pcb->extensions()->is_remote_supported(ProtocolExtension::UT_PEX))
402
if (togglePex == PeerConnectionBase::PEX_ENABLE) {
403
pcb->set_peer_exchange(true);
405
if (m_info->size_pex() >= m_info->max_size_pex())
408
} else if (!pcb->extensions()->is_local_enabled(ProtocolExtension::UT_PEX)) {
411
} else if (togglePex == PeerConnectionBase::PEX_DISABLE) {
412
pcb->set_peer_exchange(false);
417
// Still using the old buffer? Make a copy in this rare case.
418
DataBuffer* message = pcb->extension_message();
420
if (!message->empty() && (message->data() == m_ut_pex_initial.data() || message->data() == m_ut_pex_delta.data())) {
421
char* buffer = new char[message->length()];
422
memcpy(buffer, message->data(), message->length());
423
message->set(buffer, buffer + message->length(), true);
426
pcb->do_peer_exchange();
429
std::sort(current.begin(), current.end(), SocketAddressCompact_less());
431
ProtocolExtension::PEXList added;
432
added.reserve(current.size());
433
std::set_difference(current.begin(), current.end(), m_ut_pex_list.begin(), m_ut_pex_list.end(),
434
std::back_inserter(added), SocketAddressCompact_less());
436
ProtocolExtension::PEXList removed;
437
removed.reserve(m_ut_pex_list.size());
438
std::set_difference(m_ut_pex_list.begin(), m_ut_pex_list.end(), current.begin(), current.end(),
439
std::back_inserter(removed), SocketAddressCompact_less());
441
if (current.size() > m_info->max_size_pex_list()) {
442
// This test is only correct as long as we have a constant max
444
if (added.size() < current.size() - m_info->max_size_pex_list())
445
throw internal_error("DownloadMain::do_peer_exchange() added.size() < current.size() - m_info->max_size_pex_list().");
448
added.erase(added.end() - (current.size() - m_info->max_size_pex_list()), added.end());
450
// Create the new m_ut_pex_list by removing any 'removed'
451
// addresses from the original list and then adding the new
453
m_ut_pex_list.erase(std::set_difference(m_ut_pex_list.begin(), m_ut_pex_list.end(), removed.begin(), removed.end(),
454
m_ut_pex_list.begin(), SocketAddressCompact_less()), m_ut_pex_list.end());
455
m_ut_pex_list.insert(m_ut_pex_list.end(), added.begin(), added.end());
457
std::sort(m_ut_pex_list.begin(), m_ut_pex_list.end(), SocketAddressCompact_less());
460
m_ut_pex_list.swap(current);
464
m_ut_pex_delta.clear();
466
// If no peers were added or removed, the initial message is still correct and
467
// the delta message stays emptied. Otherwise generate the appropriate messages.
468
if (!added.empty() || !m_ut_pex_list.empty()) {
469
m_ut_pex_delta = ProtocolExtension::generate_ut_pex_message(added, removed);
471
m_ut_pex_initial.clear();
472
m_ut_pex_initial = ProtocolExtension::generate_ut_pex_message(m_ut_pex_list, current);
477
DownloadMain::set_metadata_size(size_t size) {
478
if (m_info->is_meta_download()) {
479
if (m_fileList.size_bytes() < 2)
480
file_list()->reset_filesize(size);
481
else if (size != m_fileList.size_bytes())
482
throw communication_error("Peer-supplied metadata size mismatch.");
484
} else if (m_info->metadata_size() && m_info->metadata_size() != size) {
485
throw communication_error("Peer-supplied metadata size mismatch.");
488
m_info->set_metadata_size(size);