~ubuntu-branches/ubuntu/wily/libtorrent/wily-proposed

« back to all changes in this revision

Viewing changes to src/torrent/download.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rogério Brito
  • Date: 2011-03-20 01:06:18 UTC
  • mfrom: (1.1.13 upstream) (4.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110320010618-g3wyylccqzqko73c
Tags: 0.12.7-5
* Use Steinar's "real" patch for IPv6. Addresses #490277, #618275,
  and Closes: #617791.
* Adapt libtorrent-0.12.6-ipv6-07.patch. It FTBFS otherwise.
* Add proper attibution to the IPv6 patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// libTorrent - BitTorrent library
 
2
// Copyright (C) 2005-2007, Jari Sundell
 
3
//
 
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.
 
8
// 
 
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.
 
13
// 
 
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
 
17
//
 
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
 
22
// including the two.
 
23
//
 
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.
 
31
//
 
32
// Contact:  Jari Sundell <jaris@ifi.uio.no>
 
33
//
 
34
//           Skomakerveien 33
 
35
//           3185 Skoppum, NORWAY
 
36
 
 
37
#include "config.h"
 
38
 
 
39
#include <rak/functional.h>
 
40
#include <sigc++/adaptors/bind.h>
 
41
#include <sigc++/adaptors/hide.h>
 
42
 
 
43
#include "data/block.h"
 
44
#include "data/block_list.h"
 
45
#include "data/chunk_list.h"
 
46
#include "data/hash_queue.h"
 
47
#include "data/hash_torrent.h"
 
48
#include "download/available_list.h"
 
49
#include "download/choke_manager.h"
 
50
#include "download/chunk_selector.h"
 
51
#include "download/chunk_statistics.h"
 
52
#include "download/download_wrapper.h"
 
53
#include "protocol/peer_connection_base.h"
 
54
#include "protocol/peer_factory.h"
 
55
#include "peer/peer_info.h"
 
56
#include "tracker/tracker_manager.h"
 
57
#include "torrent/download_info.h"
 
58
#include "torrent/data/file.h"
 
59
#include "torrent/peer/connection_list.h"
 
60
 
 
61
#include "exceptions.h"
 
62
#include "download.h"
 
63
#include "object.h"
 
64
#include "throttle.h"
 
65
#include "tracker_list.h"
 
66
 
 
67
namespace torrent {
 
68
 
 
69
const DownloadInfo*
 
70
Download::info() const { return m_ptr->info(); }
 
71
 
 
72
void
 
73
Download::open(int flags) {
 
74
  if (m_ptr->info()->is_open())
 
75
    return;
 
76
 
 
77
  // Currently always open with no_create, as start will make sure
 
78
  // they are created. Need to fix this.
 
79
  m_ptr->main()->open(FileList::open_no_create);
 
80
  m_ptr->hash_checker()->ranges().insert(0, m_ptr->main()->file_list()->size_chunks());
 
81
 
 
82
  // Mark the files by default to be created and resized. The client
 
83
  // should be allowed to pass a flag that will keep the old settings,
 
84
  // although loading resume data should really handle everything
 
85
  // properly.
 
86
  int fileFlags = File::flag_create_queued | File::flag_resize_queued;
 
87
 
 
88
  if (flags & open_enable_fallocate)
 
89
    fileFlags |= File::flag_fallocate;
 
90
 
 
91
  for (FileList::iterator itr = m_ptr->main()->file_list()->begin(), last = m_ptr->main()->file_list()->end(); itr != last; itr++)
 
92
    (*itr)->set_flags(fileFlags);
 
93
}
 
94
 
 
95
void
 
96
Download::close(int flags) {
 
97
  if (m_ptr->info()->is_active())
 
98
    stop(0);
 
99
 
 
100
  m_ptr->close();
 
101
}
 
102
 
 
103
void
 
104
Download::start(int flags) {
 
105
  if (!m_ptr->hash_checker()->is_checked())
 
106
    throw internal_error("Tried to start an unchecked download.");
 
107
 
 
108
  if (!m_ptr->info()->is_open())
 
109
    throw internal_error("Tried to start a closed download.");
 
110
 
 
111
  if (m_ptr->info()->is_active())
 
112
    return;
 
113
 
 
114
//   file_list()->open(flags);
 
115
 
 
116
  // If the FileList::open_no_create flag was not set, our new
 
117
  // behavior is to create all zero-length files with
 
118
  // flag_queued_create set.
 
119
  file_list()->open(flags & ~FileList::open_no_create);
 
120
 
 
121
  if (m_ptr->connection_type() == CONNECTION_INITIAL_SEED) {
 
122
    if (!m_ptr->main()->start_initial_seeding()) 
 
123
      set_connection_type(CONNECTION_SEED);
 
124
  }
 
125
 
 
126
  m_ptr->main()->start();
 
127
  m_ptr->main()->tracker_manager()->set_active(true);
 
128
 
 
129
  // Reset the uploaded/download baseline when we restart the download
 
130
  // so that broken trackers get the right uploaded ratio.
 
131
  if (!(flags & start_keep_baseline)) {
 
132
    m_ptr->info()->set_uploaded_baseline(m_ptr->info()->up_rate()->total());
 
133
    m_ptr->info()->set_completed_baseline(m_ptr->main()->file_list()->completed_bytes());
 
134
  }
 
135
 
 
136
  if (flags & start_skip_tracker)
 
137
    // If tracker_manager isn't active and nothing is sent, it will
 
138
    // stay stuck.
 
139
    m_ptr->main()->tracker_manager()->send_later();
 
140
  else
 
141
    m_ptr->main()->tracker_manager()->send_start();
 
142
}
 
143
 
 
144
void
 
145
Download::stop(int flags) {
 
146
  if (!m_ptr->info()->is_active())
 
147
    return;
 
148
 
 
149
  m_ptr->main()->stop();
 
150
  m_ptr->main()->tracker_manager()->set_active(false);
 
151
 
 
152
  if (!(flags & stop_skip_tracker))
 
153
    m_ptr->main()->tracker_manager()->send_stop();
 
154
}
 
155
 
 
156
bool
 
157
Download::hash_check(bool tryQuick) {
 
158
  if (m_ptr->hash_checker()->is_checking())
 
159
    throw internal_error("Download::hash_check(...) called but the hash is already being checked.");
 
160
 
 
161
  if (!m_ptr->info()->is_open() || m_ptr->info()->is_active())
 
162
    throw internal_error("Download::hash_check(...) called on a closed or active download.");
 
163
 
 
164
  if (m_ptr->hash_checker()->is_checked())
 
165
    throw internal_error("Download::hash_check(...) called but already hash checked.");
 
166
 
 
167
  Bitfield* bitfield = m_ptr->main()->file_list()->mutable_bitfield();
 
168
 
 
169
  if (bitfield->empty()) {
 
170
    // The bitfield still hasn't been allocated, so no resume data was
 
171
    // given. 
 
172
    bitfield->allocate();
 
173
    bitfield->unset_all();
 
174
 
 
175
    m_ptr->hash_checker()->ranges().insert(0, m_ptr->main()->file_list()->size_chunks());
 
176
  }
 
177
 
 
178
  m_ptr->main()->file_list()->update_completed();
 
179
 
 
180
  return m_ptr->hash_checker()->start(tryQuick);
 
181
}
 
182
 
 
183
// Propably not correct, need to clear content, etc.
 
184
void
 
185
Download::hash_stop() {
 
186
  if (!m_ptr->hash_checker()->is_checking())
 
187
    return;
 
188
 
 
189
  m_ptr->hash_checker()->ranges().erase(0, m_ptr->hash_checker()->position());
 
190
  m_ptr->hash_queue()->remove(m_ptr);
 
191
 
 
192
  m_ptr->hash_checker()->clear();
 
193
}
 
194
 
 
195
bool
 
196
Download::is_hash_checked() const {
 
197
  return m_ptr->hash_checker()->is_checked();
 
198
}
 
199
 
 
200
bool
 
201
Download::is_hash_checking() const {
 
202
  return m_ptr->hash_checker()->is_checking();
 
203
}
 
204
 
 
205
void
 
206
Download::set_pex_enabled(bool enabled) {
 
207
  m_ptr->info()->change_flags(DownloadInfo::flag_pex_enabled, enabled);
 
208
}
 
209
 
 
210
Object*
 
211
Download::bencode() {
 
212
  return m_ptr->bencode();
 
213
}
 
214
 
 
215
const Object*
 
216
Download::bencode() const {
 
217
  return m_ptr->bencode();
 
218
}
 
219
 
 
220
FileList*
 
221
Download::file_list() const {
 
222
  return m_ptr->main()->file_list();
 
223
}
 
224
 
 
225
TrackerList*
 
226
Download::tracker_list() const {
 
227
  return m_ptr->main()->tracker_manager()->container();
 
228
}
 
229
 
 
230
PeerList*
 
231
Download::peer_list() {
 
232
  return m_ptr->main()->peer_list();
 
233
}
 
234
 
 
235
const PeerList*
 
236
Download::peer_list() const {
 
237
  return m_ptr->main()->peer_list();
 
238
}
 
239
 
 
240
const TransferList*
 
241
Download::transfer_list() const {
 
242
  return m_ptr->main()->delegator()->transfer_list();
 
243
}
 
244
 
 
245
ConnectionList*
 
246
Download::connection_list() {
 
247
  return m_ptr->main()->connection_list();
 
248
}
 
249
 
 
250
const ConnectionList*
 
251
Download::connection_list() const {
 
252
  return m_ptr->main()->connection_list();
 
253
}
 
254
 
 
255
uint64_t
 
256
Download::bytes_done() const {
 
257
  uint64_t a = 0;
 
258
 
 
259
  Delegator* d = m_ptr->main()->delegator();
 
260
 
 
261
  for (TransferList::const_iterator itr1 = d->transfer_list()->begin(), last1 = d->transfer_list()->end(); itr1 != last1; ++itr1)
 
262
    for (BlockList::const_iterator itr2 = (*itr1)->begin(), last2 = (*itr1)->end(); itr2 != last2; ++itr2)
 
263
      if (itr2->is_finished())
 
264
        a += itr2->piece().length();
 
265
  
 
266
  return a + m_ptr->main()->file_list()->completed_bytes();
 
267
}
 
268
 
 
269
uint32_t 
 
270
Download::chunks_hashed() const {
 
271
  return m_ptr->hash_checker()->position();
 
272
}
 
273
 
 
274
const uint8_t*
 
275
Download::chunks_seen() const {
 
276
  return !m_ptr->main()->chunk_statistics()->empty() ? &*m_ptr->main()->chunk_statistics()->begin() : NULL;
 
277
}
 
278
 
 
279
void
 
280
Download::set_chunks_done(uint32_t chunks) {
 
281
  if (m_ptr->info()->is_open())
 
282
    throw input_error("Download::set_chunks_done(...) Download is open.");
 
283
 
 
284
  m_ptr->main()->file_list()->mutable_bitfield()->set_size_set(chunks);
 
285
}
 
286
 
 
287
void
 
288
Download::set_bitfield(bool allSet) {
 
289
  if (m_ptr->hash_checker()->is_checked() || m_ptr->hash_checker()->is_checking())
 
290
    throw input_error("Download::set_bitfield(...) Download in invalid state.");
 
291
 
 
292
  Bitfield* bitfield = m_ptr->main()->file_list()->mutable_bitfield();
 
293
 
 
294
  bitfield->allocate();
 
295
 
 
296
  if (allSet)
 
297
    bitfield->set_all();
 
298
  else
 
299
    bitfield->unset_all();
 
300
  
 
301
  m_ptr->hash_checker()->ranges().clear();
 
302
}
 
303
 
 
304
void
 
305
Download::set_bitfield(uint8_t* first, uint8_t* last) {
 
306
  if (m_ptr->hash_checker()->is_checked() || m_ptr->hash_checker()->is_checking())
 
307
    throw input_error("Download::set_bitfield(...) Download in invalid state.");
 
308
 
 
309
  if (std::distance(first, last) != (ptrdiff_t)m_ptr->main()->file_list()->bitfield()->size_bytes())
 
310
    throw input_error("Download::set_bitfield(...) Invalid length.");
 
311
 
 
312
  Bitfield* bitfield = m_ptr->main()->file_list()->mutable_bitfield();
 
313
 
 
314
  bitfield->allocate();
 
315
  std::memcpy(bitfield->begin(), first, bitfield->size_bytes());
 
316
  bitfield->update();
 
317
  
 
318
  m_ptr->hash_checker()->ranges().clear();
 
319
}
 
320
 
 
321
void
 
322
Download::update_range(int flags, uint32_t first, uint32_t last) {
 
323
  if (m_ptr->hash_checker()->is_checked() ||
 
324
      m_ptr->hash_checker()->is_checking() ||
 
325
      m_ptr->main()->file_list()->bitfield()->empty())
 
326
    throw input_error("Download::clear_range(...) Download in invalid state.");
 
327
 
 
328
  if (flags & update_range_recheck)
 
329
    m_ptr->hash_checker()->ranges().insert(first, last);
 
330
  
 
331
  if (flags & (update_range_clear | update_range_recheck))
 
332
    m_ptr->main()->file_list()->mutable_bitfield()->unset_range(first, last);
 
333
}
 
334
 
 
335
void
 
336
Download::sync_chunks() {
 
337
  m_ptr->main()->chunk_list()->sync_chunks(ChunkList::sync_all | ChunkList::sync_force);
 
338
}
 
339
 
 
340
uint32_t
 
341
Download::peers_complete() const {
 
342
  return m_ptr->main()->chunk_statistics()->complete();
 
343
}
 
344
 
 
345
uint32_t
 
346
Download::peers_accounted() const {
 
347
  return m_ptr->main()->chunk_statistics()->accounted();
 
348
}
 
349
 
 
350
uint32_t
 
351
Download::peers_currently_unchoked() const {
 
352
  return m_ptr->main()->upload_choke_manager()->size_unchoked();
 
353
}
 
354
 
 
355
uint32_t
 
356
Download::peers_currently_interested() const {
 
357
  return m_ptr->main()->upload_choke_manager()->size_total();
 
358
}
 
359
 
 
360
uint32_t
 
361
Download::size_pex() const {
 
362
  return m_ptr->main()->info()->size_pex();
 
363
}
 
364
 
 
365
uint32_t
 
366
Download::max_size_pex() const {
 
367
  return m_ptr->main()->info()->max_size_pex();
 
368
}
 
369
 
 
370
bool
 
371
Download::accepting_new_peers() const {
 
372
  return m_ptr->info()->is_accepting_new_peers();
 
373
}
 
374
 
 
375
uint32_t
 
376
Download::uploads_max() const {
 
377
  if (m_ptr->main()->upload_choke_manager()->max_unchoked() == ChokeManager::unlimited)
 
378
    return 0;
 
379
 
 
380
  return m_ptr->main()->upload_choke_manager()->max_unchoked();
 
381
}
 
382
 
 
383
void
 
384
Download::set_upload_throttle(Throttle* t) {
 
385
  if (m_ptr->info()->is_active())
 
386
    throw internal_error("Download::set_upload_throttle() called on active download.");
 
387
 
 
388
  m_ptr->main()->set_upload_throttle(t->throttle_list());
 
389
}
 
390
 
 
391
void
 
392
Download::set_download_throttle(Throttle* t) {
 
393
  if (m_ptr->info()->is_active())
 
394
    throw internal_error("Download::set_download_throttle() called on active download.");
 
395
 
 
396
  m_ptr->main()->set_download_throttle(t->throttle_list());
 
397
}
 
398
  
 
399
void
 
400
Download::set_uploads_max(uint32_t v) {
 
401
  if (v > (1 << 16)) 
 
402
    throw input_error("Max uploads must be between 0 and 2^16."); 
 
403
                 
 
404
  // For the moment, treat 0 as unlimited. 
 
405
  m_ptr->main()->upload_choke_manager()->set_max_unchoked(v == 0 ? ChokeManager::unlimited : v); 
 
406
  m_ptr->main()->upload_choke_manager()->balance();
 
407
}
 
408
 
 
409
Download::ConnectionType
 
410
Download::connection_type() const {
 
411
  return (ConnectionType)m_ptr->connection_type();
 
412
}
 
413
 
 
414
void
 
415
Download::set_connection_type(ConnectionType t) {
 
416
  if (m_ptr->info()->is_meta_download()) {
 
417
    m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionMetadata);
 
418
    return;
 
419
  }
 
420
 
 
421
  switch (t) {
 
422
  case CONNECTION_LEECH:
 
423
    m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionDefault);
 
424
    break;
 
425
  case CONNECTION_SEED:
 
426
    m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionSeed);
 
427
    break;
 
428
  case CONNECTION_INITIAL_SEED:
 
429
    if (info()->is_active() && m_ptr->main()->initial_seeding() == NULL)
 
430
      throw input_error("Can't switch to initial seeding: download is active.");
 
431
    m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionInitialSeed);
 
432
    break;
 
433
  default:
 
434
    throw input_error("torrent::Download::set_connection_type(...) received an unknown type.");
 
435
  };
 
436
 
 
437
  m_ptr->set_connection_type(t);
 
438
}
 
439
 
 
440
void
 
441
Download::update_priorities() {
 
442
  m_ptr->receive_update_priorities();
 
443
}
 
444
 
 
445
void
 
446
Download::add_peer(const sockaddr* sa, int port) {
 
447
  if (m_ptr->info()->is_private())
 
448
    return;
 
449
 
 
450
  rak::socket_address sa_port = *rak::socket_address::cast_from(sa);
 
451
  sa_port.set_port(port);
 
452
  m_ptr->main()->add_peer(sa_port);
 
453
}
 
454
 
 
455
}