~ubuntu-branches/ubuntu/trusty/miro/trusty

« back to all changes in this revision

Viewing changes to portable/libtorrent/src/torrent.cpp

  • Committer: Daniel Hahler
  • Date: 2010-04-13 18:51:35 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: ubuntu-launchpad@thequod.de-20100413185135-xi24v1diqg8w406x
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
Copyright (c) 2003, Arvid Norberg
4
 
All rights reserved.
5
 
 
6
 
Redistribution and use in source and binary forms, with or without
7
 
modification, are permitted provided that the following conditions
8
 
are met:
9
 
 
10
 
    * Redistributions of source code must retain the above copyright
11
 
      notice, this list of conditions and the following disclaimer.
12
 
    * Redistributions in binary form must reproduce the above copyright
13
 
      notice, this list of conditions and the following disclaimer in
14
 
      the documentation and/or other materials provided with the distribution.
15
 
    * Neither the name of the author nor the names of its
16
 
      contributors may be used to endorse or promote products derived
17
 
      from this software without specific prior written permission.
18
 
 
19
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
 
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 
POSSIBILITY OF SUCH DAMAGE.
30
 
 
31
 
*/
32
 
 
33
 
#include "libtorrent/pch.hpp"
34
 
 
35
 
#include <ctime>
36
 
#include <iostream>
37
 
#include <fstream>
38
 
#include <iomanip>
39
 
#include <iterator>
40
 
#include <algorithm>
41
 
#include <set>
42
 
#include <cctype>
43
 
#include <numeric>
44
 
 
45
 
#ifdef _MSC_VER
46
 
#pragma warning(push, 1)
47
 
#endif
48
 
 
49
 
#include <boost/filesystem/convenience.hpp>
50
 
#include <boost/bind.hpp>
51
 
#include <boost/thread/mutex.hpp>
52
 
 
53
 
#ifdef _MSC_VER
54
 
#pragma warning(pop)
55
 
#endif
56
 
 
57
 
#include "libtorrent/torrent_handle.hpp"
58
 
#include "libtorrent/session.hpp"
59
 
#include "libtorrent/torrent_info.hpp"
60
 
#include "libtorrent/tracker_manager.hpp"
61
 
#include "libtorrent/parse_url.hpp"
62
 
#include "libtorrent/bencode.hpp"
63
 
#include "libtorrent/hasher.hpp"
64
 
#include "libtorrent/entry.hpp"
65
 
#include "libtorrent/peer.hpp"
66
 
#include "libtorrent/bt_peer_connection.hpp"
67
 
#include "libtorrent/web_peer_connection.hpp"
68
 
#include "libtorrent/peer_id.hpp"
69
 
#include "libtorrent/alert.hpp"
70
 
#include "libtorrent/identify_client.hpp"
71
 
#include "libtorrent/alert_types.hpp"
72
 
#include "libtorrent/extensions.hpp"
73
 
#include "libtorrent/aux_/session_impl.hpp"
74
 
#include "libtorrent/instantiate_connection.hpp"
75
 
#include "libtorrent/assert.hpp"
76
 
#include "libtorrent/broadcast_socket.hpp"
77
 
 
78
 
using namespace libtorrent;
79
 
using boost::tuples::tuple;
80
 
using boost::tuples::get;
81
 
using boost::tuples::make_tuple;
82
 
using boost::bind;
83
 
using libtorrent::aux::session_impl;
84
 
 
85
 
namespace
86
 
{
87
 
 
88
 
        enum
89
 
        {
90
 
                // wait 60 seconds before retrying a failed tracker
91
 
                tracker_retry_delay_min = 60
92
 
                // when tracker_failed_max trackers
93
 
                // has failed, wait 10 minutes instead
94
 
                , tracker_retry_delay_max = 10 * 60
95
 
                , tracker_failed_max = 5
96
 
        };
97
 
 
98
 
        struct find_peer_by_ip
99
 
        {
100
 
                find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
101
 
                        : ip(a)
102
 
                        , tor(t)
103
 
                { TORRENT_ASSERT(t != 0); }
104
 
                
105
 
                bool operator()(session_impl::connection_map::value_type const& c) const
106
 
                {
107
 
                        tcp::endpoint const& sender = c->remote();
108
 
                        if (sender.address() != ip.address()) return false;
109
 
                        if (tor != c->associated_torrent().lock().get()) return false;
110
 
                        return true;
111
 
                }
112
 
 
113
 
                tcp::endpoint const& ip;
114
 
                torrent const* tor;
115
 
        };
116
 
 
117
 
        struct peer_by_id
118
 
        {
119
 
                peer_by_id(const peer_id& i): pid(i) {}
120
 
                
121
 
                bool operator()(session_impl::connection_map::value_type const& p) const
122
 
                {
123
 
                        if (p->pid() != pid) return false;
124
 
                        // have a special case for all zeros. We can have any number
125
 
                        // of peers with that pid, since it's used to indicate no pid.
126
 
                        if (std::count(pid.begin(), pid.end(), 0) == 20) return false;
127
 
                        return true;
128
 
                }
129
 
 
130
 
                peer_id const& pid;
131
 
        };
132
 
}
133
 
 
134
 
namespace libtorrent
135
 
{
136
 
 
137
 
        torrent::torrent(
138
 
                session_impl& ses
139
 
                , boost::intrusive_ptr<torrent_info> tf
140
 
                , fs::path const& save_path
141
 
                , tcp::endpoint const& net_interface
142
 
                , storage_mode_t storage_mode
143
 
                , int block_size
144
 
                , storage_constructor_type sc
145
 
                , bool paused
146
 
                , std::vector<char>* resume_data
147
 
                , int seq
148
 
                , bool auto_managed)
149
 
                : m_policy(this)
150
 
                , m_active_time(seconds(0))
151
 
                , m_seeding_time(seconds(0))
152
 
                , m_total_uploaded(0)
153
 
                , m_total_downloaded(0)
154
 
                , m_started(time_now())
155
 
                , m_last_scrape(min_time())
156
 
                , m_torrent_file(tf)
157
 
                , m_storage(0)
158
 
                , m_next_tracker_announce(time_now())
159
 
                , m_host_resolver(ses.m_io_service)
160
 
                , m_lsd_announce_timer(ses.m_io_service)
161
 
                , m_tracker_timer(ses.m_io_service)
162
 
#ifndef TORRENT_DISABLE_DHT
163
 
                , m_last_dht_announce(time_now() - minutes(15))
164
 
#endif
165
 
                , m_ses(ses)
166
 
                , m_picker(new piece_picker())
167
 
                , m_trackers(m_torrent_file->trackers())
168
 
                , m_total_failed_bytes(0)
169
 
                , m_total_redundant_bytes(0)
170
 
                , m_net_interface(net_interface.address(), 0)
171
 
                , m_save_path(complete(save_path))
172
 
                , m_storage_mode(storage_mode)
173
 
                , m_state(torrent_status::checking_resume_data)
174
 
                , m_settings(ses.settings())
175
 
                , m_storage_constructor(sc)
176
 
                , m_progress(0.f)
177
 
                , m_ratio(0.f)
178
 
                , m_max_uploads((std::numeric_limits<int>::max)())
179
 
                , m_num_uploads(0)
180
 
                , m_max_connections((std::numeric_limits<int>::max)())
181
 
                , m_block_size((std::min)(block_size, tf->piece_length()))
182
 
                , m_complete(-1)
183
 
                , m_incomplete(-1)
184
 
                , m_deficit_counter(0)
185
 
                , m_duration(1800)
186
 
                , m_sequence_number(seq)
187
 
                , m_last_working_tracker(-1)
188
 
                , m_currently_trying_tracker(0)
189
 
                , m_failed_trackers(0)
190
 
                , m_time_scaler(0)
191
 
                , m_abort(false)
192
 
                , m_paused(paused)
193
 
                , m_auto_managed(auto_managed)
194
 
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
195
 
                , m_resolving_country(false)
196
 
                , m_resolve_countries(false)
197
 
#endif
198
 
                , m_sequential_download(false)
199
 
                , m_got_tracker_response(false)
200
 
                , m_connections_initialized(true)
201
 
                , m_has_incoming(false)
202
 
                , m_files_checked(false)
203
 
                , m_queued_for_checking(false)
204
 
                , m_announcing(false)
205
 
                , m_start_sent(false)
206
 
                , m_complete_sent(false)
207
 
        {
208
 
                if (resume_data) m_resume_data.swap(*resume_data);
209
 
 
210
 
#ifndef TORRENT_DISABLE_ENCRYPTION
211
 
                hasher h;
212
 
                h.update("req2", 4);
213
 
                h.update((char*)&tf->info_hash()[0], 20);
214
 
                m_obfuscated_hash = h.final();
215
 
#endif
216
 
        }
217
 
 
218
 
        torrent::torrent(
219
 
                session_impl& ses
220
 
                , char const* tracker_url
221
 
                , sha1_hash const& info_hash
222
 
                , char const* name
223
 
                , fs::path const& save_path
224
 
                , tcp::endpoint const& net_interface
225
 
                , storage_mode_t storage_mode
226
 
                , int block_size
227
 
                , storage_constructor_type sc
228
 
                , bool paused
229
 
                , std::vector<char>* resume_data
230
 
                , int seq
231
 
                , bool auto_managed)
232
 
                : m_policy(this)
233
 
                , m_active_time(seconds(0))
234
 
                , m_seeding_time(seconds(0))
235
 
                , m_total_uploaded(0)
236
 
                , m_total_downloaded(0)
237
 
                , m_started(time_now())
238
 
                , m_last_scrape(min_time())
239
 
                , m_torrent_file(new torrent_info(info_hash))
240
 
                , m_storage(0)
241
 
                , m_next_tracker_announce(time_now())
242
 
                , m_host_resolver(ses.m_io_service)
243
 
                , m_lsd_announce_timer(ses.m_io_service)
244
 
                , m_tracker_timer(ses.m_io_service)
245
 
#ifndef TORRENT_DISABLE_DHT
246
 
                , m_last_dht_announce(time_now() - minutes(15))
247
 
#endif
248
 
                , m_ses(ses)
249
 
                , m_picker(new piece_picker())
250
 
                , m_total_failed_bytes(0)
251
 
                , m_total_redundant_bytes(0)
252
 
                , m_net_interface(net_interface.address(), 0)
253
 
                , m_save_path(complete(save_path))
254
 
                , m_storage_mode(storage_mode)
255
 
                , m_state(torrent_status::checking_resume_data)
256
 
                , m_settings(ses.settings())
257
 
                , m_storage_constructor(sc)
258
 
                , m_progress(0.f)
259
 
                , m_ratio(0.f)
260
 
                , m_max_uploads((std::numeric_limits<int>::max)())
261
 
                , m_num_uploads(0)
262
 
                , m_max_connections((std::numeric_limits<int>::max)())
263
 
                , m_block_size(block_size)
264
 
                , m_complete(-1)
265
 
                , m_incomplete(-1)
266
 
                , m_deficit_counter(0)
267
 
                , m_duration(1800)
268
 
                , m_sequence_number(seq)
269
 
                , m_last_working_tracker(-1)
270
 
                , m_currently_trying_tracker(0)
271
 
                , m_failed_trackers(0)
272
 
                , m_time_scaler(0)
273
 
                , m_abort(false)
274
 
                , m_paused(paused)
275
 
                , m_auto_managed(auto_managed)
276
 
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
277
 
                , m_resolving_country(false)
278
 
                , m_resolve_countries(false)
279
 
#endif
280
 
                , m_sequential_download(false)
281
 
                , m_got_tracker_response(false)
282
 
                , m_connections_initialized(false)
283
 
                , m_has_incoming(false)
284
 
                , m_files_checked(false)
285
 
                , m_queued_for_checking(false)
286
 
                , m_announcing(false)
287
 
                , m_start_sent(false)
288
 
                , m_complete_sent(false)
289
 
        {
290
 
                if (resume_data) m_resume_data.swap(*resume_data);
291
 
 
292
 
#ifndef TORRENT_DISABLE_ENCRYPTION
293
 
                hasher h;
294
 
                h.update("req2", 4);
295
 
                h.update((char*)&info_hash[0], 20);
296
 
                m_obfuscated_hash = h.final();
297
 
#endif
298
 
 
299
 
#ifdef TORRENT_DEBUG
300
 
                m_files_checked = false;
301
 
#endif
302
 
                INVARIANT_CHECK;
303
 
 
304
 
                if (name) m_name.reset(new std::string(name));
305
 
 
306
 
                if (tracker_url && std::strlen(tracker_url) > 0)
307
 
                {
308
 
                        m_trackers.push_back(announce_entry(tracker_url));
309
 
                        m_torrent_file->add_tracker(tracker_url);
310
 
                }
311
 
        }
312
 
 
313
 
        void torrent::start()
314
 
        {
315
 
                if (!m_resume_data.empty())
316
 
                {
317
 
                        if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0]
318
 
                                + m_resume_data.size(), m_resume_entry) != 0)
319
 
                        {
320
 
                                std::vector<char>().swap(m_resume_data);
321
 
                                if (m_ses.m_alerts.should_post<fastresume_rejected_alert>())
322
 
                                {
323
 
                                        m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed"));
324
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
325
 
                                        (*m_ses.m_logger) << "fastresume data for "
326
 
                                                << torrent_file().name() << " rejected: parse failed\n";
327
 
#endif
328
 
                                }
329
 
                        }
330
 
                }
331
 
 
332
 
                // we need to start announcing since we don't have any
333
 
                // metadata. To receive peers to ask for it.
334
 
                if (m_torrent_file->is_valid()) init();
335
 
                else
336
 
                {
337
 
                        set_state(torrent_status::downloading_metadata);
338
 
                        if (!m_trackers.empty()) start_announcing();
339
 
                }
340
 
 
341
 
                if (m_abort) return;
342
 
        }
343
 
 
344
 
#ifndef TORRENT_DISABLE_DHT
345
 
        bool torrent::should_announce_dht() const
346
 
        {
347
 
                if (m_ses.m_listen_sockets.empty()) return false;
348
 
 
349
 
                if (!m_ses.m_dht) return false;
350
 
                if (m_torrent_file->is_valid() && !m_files_checked) return false;
351
 
 
352
 
                // don't announce private torrents
353
 
                if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
354
 
                if (m_trackers.empty()) return true;
355
 
                        
356
 
                return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
357
 
        }
358
 
#endif
359
 
 
360
 
        torrent::~torrent()
361
 
        {
362
 
                // The invariant can't be maintained here, since the torrent
363
 
                // is being destructed, all weak references to it have been
364
 
                // reset, which means that all its peers already have an
365
 
                // invalidated torrent pointer (so it cannot be verified to be correct)
366
 
                
367
 
                // i.e. the invariant can only be maintained if all connections have
368
 
                // been closed by the time the torrent is destructed. And they are
369
 
                // supposed to be closed. So we can still do the invariant check.
370
 
 
371
 
                TORRENT_ASSERT(m_connections.empty());
372
 
                
373
 
                INVARIANT_CHECK;
374
 
 
375
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
376
 
                for (peer_iterator i = m_connections.begin();
377
 
                        i != m_connections.end(); ++i)
378
 
                {
379
 
                        (*(*i)->m_logger) << "*** DESTRUCTING TORRENT\n";
380
 
                }
381
 
#endif
382
 
 
383
 
                TORRENT_ASSERT(m_abort);
384
 
                if (!m_connections.empty())
385
 
                        disconnect_all();
386
 
        }
387
 
 
388
 
        peer_request torrent::to_req(piece_block const& p)
389
 
        {
390
 
                int block_offset = p.block_index * m_block_size;
391
 
                int block_size = (std::min)(torrent_file().piece_size(
392
 
                        p.piece_index) - block_offset, m_block_size);
393
 
                TORRENT_ASSERT(block_size > 0);
394
 
                TORRENT_ASSERT(block_size <= m_block_size);
395
 
 
396
 
                peer_request r;
397
 
                r.piece = p.piece_index;
398
 
                r.start = block_offset;
399
 
                r.length = block_size;
400
 
                return r;
401
 
        }
402
 
 
403
 
        std::string torrent::name() const
404
 
        {
405
 
                if (valid_metadata()) return m_torrent_file->name();
406
 
                if (m_name) return *m_name;
407
 
                return "";
408
 
        }
409
 
 
410
 
#ifndef TORRENT_DISABLE_EXTENSIONS
411
 
 
412
 
        void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
413
 
        {
414
 
                m_extensions.push_back(ext);
415
 
        }
416
 
 
417
 
        void torrent::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
418
 
                , void* userdata)
419
 
        {
420
 
                boost::shared_ptr<torrent_plugin> tp(ext(this, userdata));
421
 
                if (!tp) return;
422
 
 
423
 
                add_extension(tp);
424
 
                
425
 
                for (peer_iterator i = m_connections.begin();
426
 
                        i != m_connections.end(); ++i)
427
 
                {
428
 
                        peer_connection* p = *i;
429
 
                        boost::shared_ptr<peer_plugin> pp(tp->new_connection(p));
430
 
                        if (pp) p->add_extension(pp);
431
 
                }
432
 
 
433
 
                // if files are checked for this torrent, call the extension
434
 
                // to let it initialize itself
435
 
                if (m_connections_initialized)
436
 
                        tp->on_files_checked();
437
 
        }
438
 
 
439
 
#endif
440
 
 
441
 
        // this may not be called from a constructor because of the call to
442
 
        // shared_from_this()
443
 
        void torrent::init()
444
 
        {
445
 
                TORRENT_ASSERT(m_torrent_file->is_valid());
446
 
                TORRENT_ASSERT(m_torrent_file->num_files() > 0);
447
 
                TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
448
 
 
449
 
                m_file_priority.clear();
450
 
                m_file_priority.resize(m_torrent_file->num_files(), 1);
451
 
 
452
 
                m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
453
 
 
454
 
                if (m_torrent_file->num_pieces()
455
 
                        > piece_picker::max_pieces)
456
 
                {
457
 
                        set_error("too many pieces in torrent");
458
 
                        pause();
459
 
                }
460
 
 
461
 
                // the shared_from_this() will create an intentional
462
 
                // cycle of ownership, se the hpp file for description.
463
 
                m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
464
 
                        , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
465
 
                        , m_storage_mode);
466
 
                m_storage = m_owning_storage.get();
467
 
                m_picker->init((std::max)(m_torrent_file->piece_length() / m_block_size, 1)
468
 
                        , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
469
 
 
470
 
                std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
471
 
                std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
472
 
                        , m_web_seeds.begin()));
473
 
 
474
 
                set_state(torrent_status::checking_resume_data);
475
 
 
476
 
                if (m_resume_entry.type() == lazy_entry::dict_t)
477
 
                {
478
 
                        char const* error = 0;
479
 
                        if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
480
 
                                error = "invalid file format tag";
481
 
        
482
 
                        std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
483
 
                        if (!error && info_hash.empty())
484
 
                                error = "missing info-hash";
485
 
 
486
 
                        if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
487
 
                                error = "mismatching info-hash";
488
 
 
489
 
                        if (error && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
490
 
                        {
491
 
                                m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
492
 
                        }
493
 
 
494
 
                        if (error)
495
 
                        {
496
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
497
 
                                (*m_ses.m_logger) << "fastresume data for "
498
 
                                        << torrent_file().name() << " rejected: "
499
 
                                        << error << "\n";
500
 
#endif
501
 
                                std::vector<char>().swap(m_resume_data);
502
 
                                lazy_entry().swap(m_resume_entry);
503
 
                        }
504
 
                        else
505
 
                        {
506
 
                                read_resume_data(m_resume_entry);
507
 
                        }
508
 
                }
509
 
        
510
 
                m_storage->async_check_fastresume(&m_resume_entry
511
 
                        , bind(&torrent::on_resume_data_checked
512
 
                        , shared_from_this(), _1, _2));
513
 
        }
514
 
 
515
 
        void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
516
 
        {
517
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
518
 
 
519
 
                if (ret == piece_manager::fatal_disk_error)
520
 
                {
521
 
                        if (m_ses.m_alerts.should_post<file_error_alert>())
522
 
                        {
523
 
                                m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
524
 
                        }
525
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
526
 
                        (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
527
 
                                " error: " << j.str <<
528
 
                                " torrent: " << torrent_file().name() <<
529
 
                                " ]\n";
530
 
#endif
531
 
                        set_error(j.str);
532
 
                        pause();
533
 
 
534
 
                        std::vector<char>().swap(m_resume_data);
535
 
                        lazy_entry().swap(m_resume_entry);
536
 
 
537
 
                        return;
538
 
                }
539
 
 
540
 
                if (m_resume_entry.type() == lazy_entry::dict_t)
541
 
                {
542
 
                        // parse out "peers" from the resume data and add them to the peer list
543
 
                        if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
544
 
                        {
545
 
                                peer_id id(0);
546
 
 
547
 
                                for (int i = 0; i < peers_entry->list_size(); ++i)
548
 
                                {
549
 
                                        lazy_entry const* e = peers_entry->list_at(i);
550
 
                                        if (e->type() != lazy_entry::dict_t) continue;
551
 
                                        std::string ip = e->dict_find_string_value("ip");
552
 
                                        int port = e->dict_find_int_value("port");
553
 
                                        if (ip.empty() || port == 0) continue;
554
 
                                        error_code ec;
555
 
                                        tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port);
556
 
                                        if (ec) continue;
557
 
                                        m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
558
 
                                }
559
 
                        }
560
 
 
561
 
                        // parse out "banned_peers" and add them as banned
562
 
                        if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
563
 
                        {
564
 
                                peer_id id(0);
565
 
        
566
 
                                for (int i = 0; i < banned_peers_entry->list_size(); ++i)
567
 
                                {
568
 
                                        lazy_entry const* e = banned_peers_entry->list_at(i);
569
 
                                        if (e->type() != lazy_entry::dict_t) continue;
570
 
                                        std::string ip = e->dict_find_string_value("ip");
571
 
                                        int port = e->dict_find_int_value("port");
572
 
                                        if (ip.empty() || port == 0) continue;
573
 
                                        error_code ec;
574
 
                                        tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port);
575
 
                                        if (ec) continue;
576
 
                                        policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
577
 
                                        if (p) p->banned = true;
578
 
                                }
579
 
                        }
580
 
                }
581
 
 
582
 
                bool fastresume_rejected = !j.str.empty();
583
 
                
584
 
                if (fastresume_rejected && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
585
 
                {
586
 
                        m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), j.str));
587
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
588
 
                        (*m_ses.m_logger) << "fastresume data for "
589
 
                                << torrent_file().name() << " rejected: "
590
 
                                << j.str << "\n";
591
 
#endif
592
 
                }
593
 
 
594
 
                if (ret == 0)
595
 
                {
596
 
                        // there are either no files for this torrent
597
 
                        // or the resume_data was accepted
598
 
 
599
 
                        if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
600
 
                        {
601
 
                                // parse have bitmask
602
 
                                lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
603
 
                                if (pieces && pieces->type() == lazy_entry::string_t
604
 
                                        && int(pieces->string_length()) == m_torrent_file->num_pieces())
605
 
                                {
606
 
                                        char const* pieces_str = pieces->string_ptr();
607
 
                                        for (int i = 0, end(pieces->string_length()); i < end; ++i)
608
 
                                        {
609
 
                                                if ((pieces_str[i] & 1) == 0) continue;
610
 
                                                m_picker->we_have(i);
611
 
                                        }
612
 
                                }
613
 
                                else
614
 
                                {
615
 
                                        lazy_entry const* slots = m_resume_entry.dict_find("slots");
616
 
                                        if (slots && slots->type() == lazy_entry::list_t)
617
 
                                        {
618
 
                                                for (int i = 0; i < slots->list_size(); ++i)
619
 
                                                {
620
 
                                                        int piece = slots->list_int_value_at(i, -1);
621
 
                                                        if (piece >= 0) m_picker->we_have(piece);
622
 
                                                }
623
 
                                        }
624
 
                                }
625
 
 
626
 
                                // parse unfinished pieces
627
 
                                int num_blocks_per_piece =
628
 
                                        static_cast<int>(torrent_file().piece_length()) / block_size();
629
 
 
630
 
                                if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
631
 
                                {
632
 
                                        for (int i = 0; i < unfinished_ent->list_size(); ++i)
633
 
                                        {
634
 
                                                lazy_entry const* e = unfinished_ent->list_at(i);
635
 
                                                if (e->type() != lazy_entry::dict_t) continue;
636
 
                                                int piece = e->dict_find_int_value("piece", -1);
637
 
                                                if (piece < 0 || piece > torrent_file().num_pieces()) continue;
638
 
 
639
 
                                                if (m_picker->have_piece(piece))
640
 
                                                        m_picker->we_dont_have(piece);
641
 
 
642
 
                                                std::string bitmask = e->dict_find_string_value("bitmask");
643
 
                                                if (bitmask.empty()) continue;
644
 
 
645
 
                                                const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
646
 
                                                if ((int)bitmask.size() != num_bitmask_bytes) continue;
647
 
                                                for (int j = 0; j < num_bitmask_bytes; ++j)
648
 
                                                {
649
 
                                                        unsigned char bits = bitmask[j];
650
 
                                                        int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
651
 
                                                        for (int k = 0; k < num_bits; ++k)
652
 
                                                        {
653
 
                                                                const int bit = j * 8 + k;
654
 
                                                                if (bits & (1 << k))
655
 
                                                                {
656
 
                                                                        m_picker->mark_as_finished(piece_block(piece, bit), 0);
657
 
                                                                        if (m_picker->is_piece_finished(piece))
658
 
                                                                                async_verify_piece(piece, bind(&torrent::piece_finished
659
 
                                                                                        , shared_from_this(), piece, _1));
660
 
                                                                }
661
 
                                                        }
662
 
                                                }
663
 
                                        }
664
 
                                }
665
 
                        }
666
 
 
667
 
                        files_checked();
668
 
                }
669
 
                else
670
 
                {
671
 
                        // either the fastresume data was rejected or there are
672
 
                        // some files
673
 
                        set_state(torrent_status::queued_for_checking);
674
 
                        if (should_check_files())
675
 
                                queue_torrent_check();
676
 
                }
677
 
 
678
 
                std::vector<char>().swap(m_resume_data);
679
 
                lazy_entry().swap(m_resume_entry);
680
 
        }
681
 
 
682
 
        void torrent::queue_torrent_check()
683
 
        {
684
 
                if (m_queued_for_checking) return;
685
 
                m_queued_for_checking = true;
686
 
                m_ses.check_torrent(shared_from_this());
687
 
        }
688
 
 
689
 
        void torrent::dequeue_torrent_check()
690
 
        {
691
 
                if (!m_queued_for_checking) return;
692
 
                m_queued_for_checking = false;
693
 
                m_ses.done_checking(shared_from_this());
694
 
        }
695
 
 
696
 
        void torrent::force_recheck()
697
 
        {
698
 
                // if the torrent is already queued to check its files
699
 
                // don't do anything
700
 
                if (should_check_files()
701
 
                        || m_state == torrent_status::checking_resume_data)
702
 
                        return;
703
 
 
704
 
                disconnect_all();
705
 
 
706
 
                m_owning_storage->async_release_files();
707
 
                if (!m_picker) m_picker.reset(new piece_picker());
708
 
                m_picker->init(m_torrent_file->piece_length() / m_block_size
709
 
                        , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
710
 
                // assume that we don't have anything
711
 
                m_files_checked = false;
712
 
                set_state(torrent_status::checking_resume_data);
713
 
 
714
 
                m_policy.recalculate_connect_candidates();
715
 
 
716
 
                if (m_auto_managed)
717
 
                        set_queue_position((std::numeric_limits<int>::max)());
718
 
 
719
 
                std::vector<char>().swap(m_resume_data);
720
 
                lazy_entry().swap(m_resume_entry);
721
 
                m_storage->async_check_fastresume(&m_resume_entry
722
 
                        , bind(&torrent::on_force_recheck
723
 
                        , shared_from_this(), _1, _2));
724
 
        }
725
 
 
726
 
        void torrent::on_force_recheck(int ret, disk_io_job const& j)
727
 
        {
728
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
729
 
 
730
 
                if (ret == piece_manager::fatal_disk_error)
731
 
                {
732
 
                        if (m_ses.m_alerts.should_post<file_error_alert>())
733
 
                        {
734
 
                                m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
735
 
                        }
736
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
737
 
                        (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
738
 
                                " error: " << j.str <<
739
 
                                " torrent: " << torrent_file().name() <<
740
 
                                " ]\n";
741
 
#endif
742
 
                        set_error(j.str);
743
 
                        pause();
744
 
                        return;
745
 
                }
746
 
                if (ret == 0)
747
 
                {
748
 
                        // if there are no files, just start
749
 
                        files_checked();
750
 
                }
751
 
                else
752
 
                {
753
 
                        set_state(torrent_status::queued_for_checking);
754
 
                        if (should_check_files())
755
 
                                queue_torrent_check();
756
 
                }
757
 
        }
758
 
 
759
 
        void torrent::start_checking()
760
 
        {
761
 
                TORRENT_ASSERT(should_check_files());
762
 
                set_state(torrent_status::checking_files);
763
 
 
764
 
                m_storage->async_check_files(bind(
765
 
                        &torrent::on_piece_checked
766
 
                        , shared_from_this(), _1, _2));
767
 
        }
768
 
        
769
 
        void torrent::on_piece_checked(int ret, disk_io_job const& j)
770
 
        {
771
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
772
 
                INVARIANT_CHECK;
773
 
 
774
 
                if (ret == piece_manager::disk_check_aborted)
775
 
                {
776
 
                        pause();
777
 
                        return;
778
 
                }
779
 
                if (ret == piece_manager::fatal_disk_error)
780
 
                {
781
 
                        if (m_ses.m_alerts.should_post<file_error_alert>())
782
 
                        {
783
 
                                m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
784
 
                        }
785
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
786
 
                        (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
787
 
                                " error: " << j.str <<
788
 
                                " torrent: " << torrent_file().name() <<
789
 
                                " ]\n";
790
 
#endif
791
 
                        set_error(j.str);
792
 
                        pause();
793
 
                        return;
794
 
                }
795
 
 
796
 
                m_progress = j.piece / float(torrent_file().num_pieces());
797
 
 
798
 
                TORRENT_ASSERT(m_picker);
799
 
                if (j.offset >= 0 && !m_picker->have_piece(j.offset))
800
 
                        m_picker->we_have(j.offset);
801
 
 
802
 
                // we're not done checking yet
803
 
                // this handler will be called repeatedly until
804
 
                // we're done, or encounter a failure
805
 
                if (ret == piece_manager::need_full_check) return;
806
 
 
807
 
                dequeue_torrent_check();
808
 
                files_checked();
809
 
        }
810
 
 
811
 
        void torrent::use_interface(const char* net_interface)
812
 
        {
813
 
                INVARIANT_CHECK;
814
 
 
815
 
                error_code ec;
816
 
                address a(address::from_string(net_interface, ec));
817
 
                if (ec) return;
818
 
                m_net_interface = tcp::endpoint(a, 0);
819
 
        }
820
 
 
821
 
        void torrent::on_tracker_announce_disp(boost::weak_ptr<torrent> p
822
 
                , error_code const& e)
823
 
        {
824
 
                if (e) return;
825
 
                boost::shared_ptr<torrent> t = p.lock();
826
 
                if (!t) return;
827
 
                t->on_tracker_announce();
828
 
        }
829
 
 
830
 
        void torrent::on_tracker_announce()
831
 
        {
832
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
833
 
        
834
 
                if (m_abort) return;
835
 
                announce_with_tracker();
836
 
        }
837
 
 
838
 
        void torrent::on_lsd_announce_disp(boost::weak_ptr<torrent> p
839
 
                , error_code const& e)
840
 
        {
841
 
                if (e) return;
842
 
                boost::shared_ptr<torrent> t = p.lock();
843
 
                if (!t) return;
844
 
                t->on_lsd_announce();
845
 
        }
846
 
 
847
 
        void torrent::on_lsd_announce()
848
 
        {
849
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
850
 
 
851
 
                if (m_abort) return;
852
 
 
853
 
                TORRENT_ASSERT(!m_torrent_file->priv());
854
 
                if (m_torrent_file->is_valid() && m_torrent_file->priv())
855
 
                        return;
856
 
 
857
 
                if (is_paused()) return;
858
 
 
859
 
                boost::weak_ptr<torrent> self(shared_from_this());
860
 
 
861
 
                error_code ec;
862
 
 
863
 
                // announce on local network every 5 minutes
864
 
                m_lsd_announce_timer.expires_from_now(minutes(5), ec);
865
 
                m_lsd_announce_timer.async_wait(
866
 
                        bind(&torrent::on_lsd_announce_disp, self, _1));
867
 
 
868
 
                // announce with the local discovery service
869
 
                m_ses.announce_lsd(m_torrent_file->info_hash());
870
 
 
871
 
#ifndef TORRENT_DISABLE_DHT
872
 
                if (!m_ses.m_dht) return;
873
 
                ptime now = time_now();
874
 
                if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
875
 
                {
876
 
                        m_last_dht_announce = now;
877
 
                        m_ses.m_dht->announce(m_torrent_file->info_hash()
878
 
                                , m_ses.m_listen_sockets.front().external_port
879
 
                                , bind(&torrent::on_dht_announce_response_disp, self, _1));
880
 
                }
881
 
#endif
882
 
        }
883
 
 
884
 
#ifndef TORRENT_DISABLE_DHT
885
 
 
886
 
        void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
887
 
                , std::vector<tcp::endpoint> const& peers)
888
 
        {
889
 
                boost::shared_ptr<libtorrent::torrent> tor = t.lock();
890
 
                if (!tor) return;
891
 
                tor->on_dht_announce_response(peers);
892
 
        }
893
 
 
894
 
        void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
895
 
        {
896
 
                if (peers.empty()) return;
897
 
 
898
 
                if (m_ses.m_alerts.should_post<dht_reply_alert>())
899
 
                {
900
 
                        m_ses.m_alerts.post_alert(dht_reply_alert(
901
 
                                get_handle(), peers.size()));
902
 
                }
903
 
                std::for_each(peers.begin(), peers.end(), bind(
904
 
                        &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
905
 
                        , peer_info::dht, 0));
906
 
        }
907
 
 
908
 
#endif
909
 
 
910
 
        void torrent::announce_with_tracker(tracker_request::event_t e)
911
 
        {
912
 
                INVARIANT_CHECK;
913
 
 
914
 
                if (m_trackers.empty()) return;
915
 
 
916
 
                if (m_currently_trying_tracker < 0) m_currently_trying_tracker = 0;
917
 
 
918
 
                restart_tracker_timer(time_now() + seconds(tracker_retry_delay_max));
919
 
 
920
 
                if (m_abort) e = tracker_request::stopped;
921
 
 
922
 
                if (e == tracker_request::none)
923
 
                {
924
 
                        if (!m_start_sent) e = tracker_request::started;
925
 
                        if (!m_complete_sent && is_seed()) e = tracker_request::completed;
926
 
                }
927
 
 
928
 
                tracker_request req;
929
 
                req.info_hash = m_torrent_file->info_hash();
930
 
                req.pid = m_ses.get_peer_id();
931
 
                req.downloaded = m_stat.total_payload_download();
932
 
                req.uploaded = m_stat.total_payload_upload();
933
 
                req.left = bytes_left();
934
 
                if (req.left == -1) req.left = 16*1024;
935
 
                req.event = e;
936
 
                error_code ec;
937
 
                tcp::endpoint ep;
938
 
                ep = m_ses.get_ipv6_interface();
939
 
                if (ep != tcp::endpoint()) req.ipv6 = ep.address().to_string(ec);
940
 
                ep = m_ses.get_ipv4_interface();
941
 
                if (ep != tcp::endpoint()) req.ipv4 = ep.address().to_string(ec);
942
 
 
943
 
                req.url = m_trackers[m_currently_trying_tracker].url;
944
 
                // if we are aborting. we don't want any new peers
945
 
                req.num_want = (req.event == tracker_request::stopped)
946
 
                        ?0:m_settings.num_want;
947
 
 
948
 
                req.listen_port = m_ses.m_listen_sockets.empty()
949
 
                        ?0:m_ses.m_listen_sockets.front().external_port;
950
 
                req.key = m_ses.m_key;
951
 
 
952
 
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
953
 
                if (m_abort)
954
 
                {
955
 
                        boost::shared_ptr<aux::tracker_logger> tl(new aux::tracker_logger(m_ses));
956
 
                        m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
957
 
                                , tracker_login(), m_ses.m_listen_interface.address(), tl);
958
 
                }
959
 
                else
960
 
#endif
961
 
                m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
962
 
                        , tracker_login(), m_ses.m_listen_interface.address()
963
 
                        , m_abort?boost::shared_ptr<torrent>():shared_from_this());
964
 
 
965
 
                if (m_ses.m_alerts.should_post<tracker_announce_alert>())
966
 
                {
967
 
                        m_ses.m_alerts.post_alert(
968
 
                                tracker_announce_alert(get_handle(), req.url, req.event));
969
 
                }
970
 
        }
971
 
 
972
 
        void torrent::scrape_tracker()
973
 
        {
974
 
                if (m_trackers.empty()) return;
975
 
 
976
 
                TORRENT_ASSERT(m_currently_trying_tracker >= 0);
977
 
                TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size()));
978
 
                
979
 
                tracker_request req;
980
 
                req.info_hash = m_torrent_file->info_hash();
981
 
                req.kind = tracker_request::scrape_request;
982
 
                req.url = m_trackers[m_currently_trying_tracker].url;
983
 
                m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
984
 
                        , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
985
 
 
986
 
                m_last_scrape = time_now();
987
 
        }
988
 
 
989
 
        void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
990
 
        {
991
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
992
 
 
993
 
                INVARIANT_CHECK;
994
 
 
995
 
                if (m_ses.m_alerts.should_post<tracker_warning_alert>())
996
 
                        m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), req.url, msg));
997
 
        }
998
 
        
999
 
        void torrent::tracker_scrape_response(tracker_request const& req
1000
 
                , int complete, int incomplete, int downloaded)
1001
 
        {
1002
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1003
 
 
1004
 
                INVARIANT_CHECK;
1005
 
                TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
1006
 
 
1007
 
                if (complete >= 0) m_complete = complete;
1008
 
                if (incomplete >= 0) m_incomplete = incomplete;
1009
 
 
1010
 
                if (m_ses.m_alerts.should_post<scrape_reply_alert>())
1011
 
                {
1012
 
                        m_ses.m_alerts.post_alert(scrape_reply_alert(
1013
 
                                get_handle(), m_incomplete, m_complete, req.url));
1014
 
                }
1015
 
        }
1016
 
 
1017
 
        void torrent::tracker_response(
1018
 
                tracker_request const& r
1019
 
                , std::vector<peer_entry>& peer_list
1020
 
                , int interval
1021
 
                , int complete
1022
 
                , int incomplete
1023
 
                , address const& external_ip)
1024
 
        {
1025
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1026
 
 
1027
 
                INVARIANT_CHECK;
1028
 
                TORRENT_ASSERT(r.kind == tracker_request::announce_request);
1029
 
 
1030
 
                if (external_ip != address())
1031
 
                        m_ses.set_external_address(external_ip);
1032
 
 
1033
 
                if (!m_start_sent && r.event == tracker_request::started)
1034
 
                        m_start_sent = true;
1035
 
                if (!m_complete_sent && r.event == tracker_request::completed)
1036
 
                        m_complete_sent = true;
1037
 
 
1038
 
                m_failed_trackers = 0;
1039
 
 
1040
 
                if (interval < m_ses.settings().min_announce_interval)
1041
 
                        interval = m_ses.settings().min_announce_interval;
1042
 
 
1043
 
                m_last_working_tracker
1044
 
                        = prioritize_tracker(m_currently_trying_tracker);
1045
 
                m_currently_trying_tracker = 0;
1046
 
 
1047
 
                m_duration = interval;
1048
 
                restart_tracker_timer(time_now() + seconds(m_duration));
1049
 
 
1050
 
                if (complete >= 0) m_complete = complete;
1051
 
                if (incomplete >= 0) m_incomplete = incomplete;
1052
 
                if (complete >= 0 && incomplete >= 0)
1053
 
                        m_last_scrape = time_now();
1054
 
 
1055
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
1056
 
                std::stringstream s;
1057
 
                s << "TRACKER RESPONSE:\n"
1058
 
                        "interval: " << m_duration << "\n"
1059
 
                        "peers:\n";
1060
 
                for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
1061
 
                        i != peer_list.end(); ++i)
1062
 
                {
1063
 
                        s << "  " << std::setfill(' ') << std::setw(16) << i->ip
1064
 
                                << " " << std::setw(5) << std::dec << i->port << "  ";
1065
 
                        if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
1066
 
                        s << "\n";
1067
 
                }
1068
 
                s << "external ip: " << external_ip << "\n";
1069
 
                debug_log(s.str());
1070
 
#endif
1071
 
                // for each of the peers we got from the tracker
1072
 
                for (std::vector<peer_entry>::iterator i = peer_list.begin();
1073
 
                        i != peer_list.end(); ++i)
1074
 
                {
1075
 
                        // don't make connections to ourself
1076
 
                        if (i->pid == m_ses.get_peer_id())
1077
 
                                continue;
1078
 
 
1079
 
                        error_code ec;
1080
 
                        tcp::endpoint a(address::from_string(i->ip, ec), i->port);
1081
 
 
1082
 
                        if (ec)
1083
 
                        {
1084
 
                                // assume this is because we got a hostname instead of
1085
 
                                // an ip address from the tracker
1086
 
 
1087
 
                                tcp::resolver::query q(i->ip, to_string(i->port).elems);
1088
 
                                m_host_resolver.async_resolve(q,
1089
 
                                        bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
1090
 
                        }
1091
 
                        else
1092
 
                        {
1093
 
                                m_policy.peer_from_tracker(a, i->pid, peer_info::tracker, 0);
1094
 
                        }
1095
 
                }
1096
 
 
1097
 
                if (m_ses.m_alerts.should_post<tracker_reply_alert>())
1098
 
                {
1099
 
                        m_ses.m_alerts.post_alert(tracker_reply_alert(
1100
 
                                get_handle(), peer_list.size(), r.url));
1101
 
                }
1102
 
                m_got_tracker_response = true;
1103
 
        }
1104
 
 
1105
 
        void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
1106
 
                , peer_id pid)
1107
 
        {
1108
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1109
 
 
1110
 
                INVARIANT_CHECK;
1111
 
 
1112
 
                if (e || host == tcp::resolver::iterator() ||
1113
 
                        m_ses.is_aborted()) return;
1114
 
 
1115
 
                if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
1116
 
                {
1117
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1118
 
                        error_code ec;
1119
 
                        debug_log("blocked ip from tracker: " + host->endpoint().address().to_string(ec));
1120
 
#endif
1121
 
                        if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1122
 
                        {
1123
 
                                m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()));
1124
 
                        }
1125
 
 
1126
 
                        return;
1127
 
                }
1128
 
                        
1129
 
                m_policy.peer_from_tracker(*host, pid, peer_info::tracker, 0);
1130
 
        }
1131
 
 
1132
 
        size_type torrent::bytes_left() const
1133
 
        {
1134
 
                // if we don't have the metadata yet, we
1135
 
                // cannot tell how big the torrent is.
1136
 
                if (!valid_metadata()) return -1;
1137
 
                return m_torrent_file->total_size()
1138
 
                        - quantized_bytes_done();
1139
 
        }
1140
 
 
1141
 
        size_type torrent::quantized_bytes_done() const
1142
 
        {
1143
 
//              INVARIANT_CHECK;
1144
 
 
1145
 
                if (!valid_metadata()) return 0;
1146
 
 
1147
 
                if (m_torrent_file->num_pieces() == 0)
1148
 
                        return 0;
1149
 
 
1150
 
                if (is_seed()) return m_torrent_file->total_size();
1151
 
 
1152
 
                const int last_piece = m_torrent_file->num_pieces() - 1;
1153
 
 
1154
 
                size_type total_done
1155
 
                        = size_type(num_have()) * m_torrent_file->piece_length();
1156
 
 
1157
 
                // if we have the last piece, we have to correct
1158
 
                // the amount we have, since the first calculation
1159
 
                // assumed all pieces were of equal size
1160
 
                if (m_picker->have_piece(last_piece))
1161
 
                {
1162
 
                        int corr = m_torrent_file->piece_size(last_piece)
1163
 
                                - m_torrent_file->piece_length();
1164
 
                        total_done += corr;
1165
 
                }
1166
 
                return total_done;
1167
 
        }
1168
 
 
1169
 
        // the first value is the total number of bytes downloaded
1170
 
        // the second value is the number of bytes of those that haven't
1171
 
        // been filtered as not wanted we have downloaded
1172
 
        tuple<size_type, size_type> torrent::bytes_done() const
1173
 
        {
1174
 
                INVARIANT_CHECK;
1175
 
 
1176
 
                if (!valid_metadata() || m_torrent_file->num_pieces() == 0)
1177
 
                        return tuple<size_type, size_type>(0,0);
1178
 
 
1179
 
                const int last_piece = m_torrent_file->num_pieces() - 1;
1180
 
                const int piece_size = m_torrent_file->piece_length();
1181
 
 
1182
 
                if (is_seed())
1183
 
                        return make_tuple(m_torrent_file->total_size()
1184
 
                                , m_torrent_file->total_size());
1185
 
 
1186
 
                TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1187
 
                size_type wanted_done = size_type(num_have() - m_picker->num_have_filtered())
1188
 
                        * piece_size;
1189
 
                TORRENT_ASSERT(wanted_done >= 0);
1190
 
                
1191
 
                size_type total_done
1192
 
                        = size_type(num_have()) * piece_size;
1193
 
                TORRENT_ASSERT(num_have() < m_torrent_file->num_pieces());
1194
 
 
1195
 
                // if we have the last piece, we have to correct
1196
 
                // the amount we have, since the first calculation
1197
 
                // assumed all pieces were of equal size
1198
 
                if (m_picker->have_piece(last_piece))
1199
 
                {
1200
 
                        TORRENT_ASSERT(total_done >= piece_size);
1201
 
                        int corr = m_torrent_file->piece_size(last_piece)
1202
 
                                - piece_size;
1203
 
                        TORRENT_ASSERT(corr <= 0);
1204
 
                        TORRENT_ASSERT(corr > -piece_size);
1205
 
                        total_done += corr;
1206
 
                        if (m_picker->piece_priority(last_piece) != 0)
1207
 
                        {
1208
 
                                TORRENT_ASSERT(wanted_done >= piece_size);
1209
 
                                wanted_done += corr;
1210
 
                        }
1211
 
                }
1212
 
 
1213
 
                TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1214
 
                TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1215
 
                TORRENT_ASSERT(total_done >= wanted_done);
1216
 
 
1217
 
                const std::vector<piece_picker::downloading_piece>& dl_queue
1218
 
                        = m_picker->get_download_queue();
1219
 
 
1220
 
                const int blocks_per_piece = (piece_size + m_block_size - 1) / m_block_size;
1221
 
 
1222
 
                for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1223
 
                        dl_queue.begin(); i != dl_queue.end(); ++i)
1224
 
                {
1225
 
                        int corr = 0;
1226
 
                        int index = i->index;
1227
 
                        if (m_picker->have_piece(index)) continue;
1228
 
                        TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
1229
 
 
1230
 
#ifdef TORRENT_DEBUG
1231
 
                        for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
1232
 
                                j != dl_queue.end(); ++j)
1233
 
                        {
1234
 
                                TORRENT_ASSERT(j->index != index);
1235
 
                        }
1236
 
#endif
1237
 
 
1238
 
                        for (int j = 0; j < blocks_per_piece; ++j)
1239
 
                        {
1240
 
                                TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
1241
 
                                corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
1242
 
                                TORRENT_ASSERT(corr >= 0);
1243
 
                                TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
1244
 
                                        || i->info[j].state != piece_picker::block_info::state_finished);
1245
 
                        }
1246
 
 
1247
 
                        // correction if this was the last piece
1248
 
                        // and if we have the last block
1249
 
                        if (i->index == last_piece
1250
 
                                && i->info[m_picker->blocks_in_last_piece()-1].state
1251
 
                                        == piece_picker::block_info::state_finished)
1252
 
                        {
1253
 
                                corr -= m_block_size;
1254
 
                                corr += m_torrent_file->piece_size(last_piece) % m_block_size;
1255
 
                        }
1256
 
                        total_done += corr;
1257
 
                        if (m_picker->piece_priority(index) != 0)
1258
 
                                wanted_done += corr;
1259
 
                }
1260
 
 
1261
 
                TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1262
 
                TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1263
 
 
1264
 
                std::map<piece_block, int> downloading_piece;
1265
 
                for (const_peer_iterator i = begin(); i != end(); ++i)
1266
 
                {
1267
 
                        peer_connection* pc = *i;
1268
 
                        boost::optional<piece_block_progress> p
1269
 
                                = pc->downloading_piece_progress();
1270
 
                        if (p)
1271
 
                        {
1272
 
                                if (m_picker->have_piece(p->piece_index))
1273
 
                                        continue;
1274
 
 
1275
 
                                piece_block block(p->piece_index, p->block_index);
1276
 
                                if (m_picker->is_finished(block))
1277
 
                                        continue;
1278
 
 
1279
 
                                std::map<piece_block, int>::iterator dp
1280
 
                                        = downloading_piece.find(block);
1281
 
                                if (dp != downloading_piece.end())
1282
 
                                {
1283
 
                                        if (dp->second < p->bytes_downloaded)
1284
 
                                                dp->second = p->bytes_downloaded;
1285
 
                                }
1286
 
                                else
1287
 
                                {
1288
 
                                        downloading_piece[block] = p->bytes_downloaded;
1289
 
                                }
1290
 
#ifdef TORRENT_DEBUG
1291
 
                                TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes);
1292
 
                                int last_piece = m_torrent_file->num_pieces() - 1;
1293
 
                                if (p->piece_index == last_piece
1294
 
                                        && p->block_index == m_torrent_file->piece_size(last_piece) / block_size())
1295
 
                                        TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size());
1296
 
                                else
1297
 
                                        TORRENT_ASSERT(p->full_block_bytes == block_size());
1298
 
#endif
1299
 
                        }
1300
 
                }
1301
 
                for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1302
 
                        i != downloading_piece.end(); ++i)
1303
 
                {
1304
 
                        total_done += i->second;
1305
 
                        if (m_picker->piece_priority(i->first.piece_index) != 0)
1306
 
                                wanted_done += i->second;
1307
 
                }
1308
 
 
1309
 
                TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1310
 
                TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1311
 
 
1312
 
#ifdef TORRENT_DEBUG
1313
 
 
1314
 
                if (total_done >= m_torrent_file->total_size())
1315
 
                {
1316
 
                        // Thist happens when a piece has been downloaded completely
1317
 
                        // but not yet verified against the hash
1318
 
                        std::cerr << "num_have: " << num_have() << std::endl;
1319
 
                        
1320
 
                        std::cerr << "unfinished:" << std::endl;
1321
 
                        
1322
 
                        for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1323
 
                                dl_queue.begin(); i != dl_queue.end(); ++i)
1324
 
                        {
1325
 
                                std::cerr << "   " << i->index << " ";
1326
 
                                for (int j = 0; j < blocks_per_piece; ++j)
1327
 
                                {
1328
 
                                        std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
1329
 
                                }
1330
 
                                std::cerr << std::endl;
1331
 
                        }
1332
 
                        
1333
 
                        std::cerr << "downloading pieces:" << std::endl;
1334
 
 
1335
 
                        for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1336
 
                                i != downloading_piece.end(); ++i)
1337
 
                        {
1338
 
                                std::cerr << "   " << i->first.piece_index << ":" << i->first.block_index
1339
 
                                        << "  " << i->second << std::endl;
1340
 
                        }
1341
 
 
1342
 
                }
1343
 
 
1344
 
                TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1345
 
                TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1346
 
 
1347
 
#endif
1348
 
 
1349
 
                TORRENT_ASSERT(total_done >= wanted_done);
1350
 
                return make_tuple(total_done, wanted_done);
1351
 
        }
1352
 
 
1353
 
        // passed_hash_check
1354
 
        // 0: success, piece passed check
1355
 
        // -1: disk failure
1356
 
        // -2: piece failed check
1357
 
        void torrent::piece_finished(int index, int passed_hash_check)
1358
 
        {
1359
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1360
 
 
1361
 
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
1362
 
                (*m_ses.m_logger) << time_now_string() << " *** PIECE_FINISHED [ p: "
1363
 
                        << index << " chk: " << ((passed_hash_check == 0)
1364
 
                                ?"passed":passed_hash_check == -1
1365
 
                                ?"disk failed":"failed") << " ]\n";
1366
 
#endif
1367
 
 
1368
 
                TORRENT_ASSERT(valid_metadata());
1369
 
 
1370
 
                if (passed_hash_check == 0)
1371
 
                {
1372
 
                        // the following call may cause picker to become invalid
1373
 
                        // in case we just became a seed
1374
 
                        piece_passed(index);
1375
 
                }
1376
 
                else if (passed_hash_check == -2)
1377
 
                {
1378
 
                        // piece_failed() will restore the piece
1379
 
                        piece_failed(index);
1380
 
                }
1381
 
                else
1382
 
                {
1383
 
                        TORRENT_ASSERT(passed_hash_check == -1);
1384
 
                        m_picker->restore_piece(index);
1385
 
                        restore_piece_state(index);
1386
 
                }
1387
 
        }
1388
 
 
1389
 
        void torrent::piece_passed(int index)
1390
 
        {
1391
 
//              INVARIANT_CHECK;
1392
 
 
1393
 
                TORRENT_ASSERT(index >= 0);
1394
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1395
 
 
1396
 
                if (m_ses.m_alerts.should_post<piece_finished_alert>())
1397
 
                {
1398
 
                        m_ses.m_alerts.post_alert(piece_finished_alert(get_handle()
1399
 
                                , index));
1400
 
                }
1401
 
 
1402
 
                bool was_finished = m_picker->num_filtered() + num_have()
1403
 
                        == torrent_file().num_pieces();
1404
 
 
1405
 
                std::vector<void*> downloaders;
1406
 
                m_picker->get_downloaders(downloaders, index);
1407
 
 
1408
 
                // increase the trust point of all peers that sent
1409
 
                // parts of this piece.
1410
 
                std::set<void*> peers;
1411
 
                std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1412
 
 
1413
 
                m_picker->we_have(index);
1414
 
                for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
1415
 
                {
1416
 
                        peer_connection* p = *i;
1417
 
                        ++i;
1418
 
                        p->announce_piece(index);
1419
 
                }
1420
 
 
1421
 
                for (std::set<void*>::iterator i = peers.begin()
1422
 
                        , end(peers.end()); i != end; ++i)
1423
 
                {
1424
 
                        policy::peer* p = static_cast<policy::peer*>(*i);
1425
 
                        if (p == 0) continue;
1426
 
                        p->on_parole = false;
1427
 
                        ++p->trust_points;
1428
 
                        // TODO: make this limit user settable
1429
 
                        if (p->trust_points > 20) p->trust_points = 20;
1430
 
                        if (p->connection) p->connection->received_valid_data(index);
1431
 
                }
1432
 
 
1433
 
#ifndef TORRENT_DISABLE_EXTENSIONS
1434
 
                for (extension_list_t::iterator i = m_extensions.begin()
1435
 
                        , end(m_extensions.end()); i != end; ++i)
1436
 
                {
1437
 
#ifndef BOOST_NO_EXCEPTIONS
1438
 
                        try {
1439
 
#endif
1440
 
                                (*i)->on_piece_pass(index);
1441
 
#ifndef BOOST_NO_EXCEPTIONS
1442
 
                        } catch (std::exception&) {}
1443
 
#endif
1444
 
                }
1445
 
#endif
1446
 
 
1447
 
                // since this piece just passed, we might have
1448
 
                // become uninterested in some peers where this
1449
 
                // was the last piece we were interested in
1450
 
                for (peer_iterator i = m_connections.begin();
1451
 
                        i != m_connections.end();)
1452
 
                {
1453
 
                        peer_connection* p = *i;
1454
 
                        // update_interest may disconnect the peer and
1455
 
                        // invalidate the iterator
1456
 
                        ++i;
1457
 
                        // if we're not interested already, no need to check
1458
 
                        if (!p->is_interesting()) continue;
1459
 
                        // if the peer doesn't have the piece we just got, it
1460
 
                        // wouldn't affect our interest
1461
 
                        if (!p->has_piece(index)) continue;
1462
 
                        p->update_interest();
1463
 
                }
1464
 
 
1465
 
                if (!was_finished && is_finished())
1466
 
                {
1467
 
                        // torrent finished
1468
 
                        // i.e. all the pieces we're interested in have
1469
 
                        // been downloaded. Release the files (they will open
1470
 
                        // in read only mode if needed)
1471
 
                        finished();
1472
 
                        // if we just became a seed, picker is now invalid, since it
1473
 
                        // is deallocated by the torrent once it starts seeding
1474
 
                }
1475
 
        }
1476
 
 
1477
 
        void torrent::piece_failed(int index)
1478
 
        {
1479
 
                // if the last piece fails the peer connection will still
1480
 
                // think that it has received all of it until this function
1481
 
                // resets the download queue. So, we cannot do the
1482
 
                // invariant check here since it assumes:
1483
 
                // (total_done == m_torrent_file->total_size()) => is_seed()
1484
 
                INVARIANT_CHECK;
1485
 
 
1486
 
                TORRENT_ASSERT(m_storage);
1487
 
                TORRENT_ASSERT(m_storage->refcount() > 0);
1488
 
                TORRENT_ASSERT(m_picker.get());
1489
 
                TORRENT_ASSERT(index >= 0);
1490
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1491
 
 
1492
 
                if (m_ses.m_alerts.should_post<hash_failed_alert>())
1493
 
                        m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index));
1494
 
 
1495
 
                // increase the total amount of failed bytes
1496
 
                add_failed_bytes(m_torrent_file->piece_size(index));
1497
 
 
1498
 
                std::vector<void*> downloaders;
1499
 
                m_picker->get_downloaders(downloaders, index);
1500
 
 
1501
 
                // decrease the trust point of all peers that sent
1502
 
                // parts of this piece.
1503
 
                // first, build a set of all peers that participated
1504
 
                std::set<void*> peers;
1505
 
                std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1506
 
 
1507
 
#ifdef TORRENT_DEBUG
1508
 
                for (std::vector<void*>::iterator i = downloaders.begin()
1509
 
                        , end(downloaders.end()); i != end; ++i)
1510
 
                {
1511
 
                        policy::peer* p = (policy::peer*)*i;
1512
 
                        if (p && p->connection)
1513
 
                        {
1514
 
                                p->connection->piece_failed = true;
1515
 
                        }
1516
 
                }
1517
 
#endif
1518
 
 
1519
 
#ifndef TORRENT_DISABLE_EXTENSIONS
1520
 
                for (extension_list_t::iterator i = m_extensions.begin()
1521
 
                        , end(m_extensions.end()); i != end; ++i)
1522
 
                {
1523
 
#ifndef BOOST_NO_EXCEPTIONS
1524
 
                        try {
1525
 
#endif
1526
 
                                (*i)->on_piece_failed(index);
1527
 
#ifndef BOOST_NO_EXCEPTIONS
1528
 
                        } catch (std::exception&) {}
1529
 
#endif
1530
 
                }
1531
 
#endif
1532
 
 
1533
 
                for (std::set<void*>::iterator i = peers.begin()
1534
 
                        , end(peers.end()); i != end; ++i)
1535
 
                {
1536
 
                        policy::peer* p = static_cast<policy::peer*>(*i);
1537
 
                        if (p == 0) continue;
1538
 
                        if (p->connection) p->connection->received_invalid_data(index);
1539
 
 
1540
 
                        // either, we have received too many failed hashes
1541
 
                        // or this was the only peer that sent us this piece.
1542
 
                        // TODO: make this a changable setting
1543
 
                        if (p->trust_points <= -7
1544
 
                                || peers.size() == 1)
1545
 
                        {
1546
 
                                // we don't trust this peer anymore
1547
 
                                // ban it.
1548
 
                                if (m_ses.m_alerts.should_post<peer_ban_alert>())
1549
 
                                {
1550
 
                                        peer_id pid(0);
1551
 
                                        if (p->connection) pid = p->connection->pid();
1552
 
                                        m_ses.m_alerts.post_alert(peer_ban_alert(
1553
 
                                                get_handle(), p->ip(), pid));
1554
 
                                }
1555
 
 
1556
 
                                // mark the peer as banned
1557
 
                                m_policy.ban_peer(p);
1558
 
 
1559
 
                                if (p->connection)
1560
 
                                {
1561
 
#ifdef TORRENT_LOGGING
1562
 
                                        (*m_ses.m_logger) << time_now_string() << " *** BANNING PEER [ " << p->ip()
1563
 
                                                << " ] 'too many corrupt pieces'\n";
1564
 
#endif
1565
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1566
 
                                        (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip()
1567
 
                                                << " ] 'too many corrupt pieces'\n";
1568
 
#endif
1569
 
                                        p->connection->disconnect("too many corrupt pieces, banning peer");
1570
 
                                }
1571
 
                        }
1572
 
                }
1573
 
 
1574
 
                // we have to let the piece_picker know that
1575
 
                // this piece failed the check as it can restore it
1576
 
                // and mark it as being interesting for download
1577
 
                // TODO: do this more intelligently! and keep track
1578
 
                // of how much crap (data that failed hash-check) and
1579
 
                // how much redundant data we have downloaded
1580
 
                // if some clients has sent more than one piece
1581
 
                // start with redownloading the pieces that the client
1582
 
                // that has sent the least number of pieces
1583
 
                m_picker->restore_piece(index);
1584
 
                restore_piece_state(index);
1585
 
                TORRENT_ASSERT(m_storage);
1586
 
 
1587
 
                TORRENT_ASSERT(m_picker->have_piece(index) == false);
1588
 
 
1589
 
#ifdef TORRENT_DEBUG
1590
 
                for (std::vector<void*>::iterator i = downloaders.begin()
1591
 
                        , end(downloaders.end()); i != end; ++i)
1592
 
                {
1593
 
                        policy::peer* p = (policy::peer*)*i;
1594
 
                        if (p && p->connection)
1595
 
                        {
1596
 
                                p->connection->piece_failed = false;
1597
 
                        }
1598
 
                }
1599
 
#endif
1600
 
        }
1601
 
 
1602
 
        void torrent::restore_piece_state(int index)
1603
 
        {
1604
 
                TORRENT_ASSERT(has_picker());
1605
 
                for (peer_iterator i = m_connections.begin();
1606
 
                        i != m_connections.end(); ++i)
1607
 
                {
1608
 
                        peer_connection* p = *i;
1609
 
                        std::deque<pending_block> const& dq = p->download_queue();
1610
 
                        std::deque<piece_block> const& rq = p->request_queue();
1611
 
                        for (std::deque<pending_block>::const_iterator k = dq.begin()
1612
 
                                , end(dq.end()); k != end; ++k)
1613
 
                        {
1614
 
                                if (k->block.piece_index != index) continue;
1615
 
                                m_picker->mark_as_downloading(k->block, p->peer_info_struct()
1616
 
                                        , (piece_picker::piece_state_t)p->peer_speed());
1617
 
                        }
1618
 
                        for (std::deque<piece_block>::const_iterator k = rq.begin()
1619
 
                                , end(rq.end()); k != end; ++k)
1620
 
                        {
1621
 
                                if (k->piece_index != index) continue;
1622
 
                                m_picker->mark_as_downloading(*k, p->peer_info_struct()
1623
 
                                        , (piece_picker::piece_state_t)p->peer_speed());
1624
 
                        }
1625
 
                }
1626
 
        }
1627
 
 
1628
 
        void torrent::abort()
1629
 
        {
1630
 
                INVARIANT_CHECK;
1631
 
 
1632
 
                if (m_abort) return;
1633
 
 
1634
 
                m_abort = true;
1635
 
                // if the torrent is paused, it doesn't need
1636
 
                // to announce with even=stopped again.
1637
 
                if (!is_paused())
1638
 
                {
1639
 
                        stop_announcing();
1640
 
                }
1641
 
 
1642
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1643
 
                for (peer_iterator i = m_connections.begin();
1644
 
                        i != m_connections.end(); ++i)
1645
 
                {
1646
 
                        (*(*i)->m_logger) << "*** ABORTING TORRENT\n";
1647
 
                }
1648
 
#endif
1649
 
 
1650
 
                // disconnect all peers and close all
1651
 
                // files belonging to the torrents
1652
 
                disconnect_all();
1653
 
                if (m_owning_storage.get())
1654
 
                {
1655
 
                        m_storage->async_release_files(
1656
 
                                bind(&torrent::on_files_released, shared_from_this(), _1, _2));
1657
 
                        m_storage->abort_disk_io();
1658
 
                }
1659
 
                
1660
 
                dequeue_torrent_check();
1661
 
                
1662
 
                if (m_state == torrent_status::checking_files)
1663
 
                        set_state(torrent_status::queued_for_checking);
1664
 
 
1665
 
                m_owning_storage = 0;
1666
 
                m_host_resolver.cancel();
1667
 
        }
1668
 
 
1669
 
        void torrent::on_files_deleted(int ret, disk_io_job const& j)
1670
 
        {
1671
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1672
 
 
1673
 
                if (ret != 0)
1674
 
                {
1675
 
                        if (alerts().should_post<torrent_delete_failed_alert>())
1676
 
                                alerts().post_alert(torrent_delete_failed_alert(get_handle(), j.str));
1677
 
                }
1678
 
                else
1679
 
                {
1680
 
                        if (alerts().should_post<torrent_deleted_alert>())
1681
 
                                alerts().post_alert(torrent_deleted_alert(get_handle()));
1682
 
                }
1683
 
        }
1684
 
 
1685
 
        void torrent::on_files_released(int ret, disk_io_job const& j)
1686
 
        {
1687
 
/*
1688
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1689
 
 
1690
 
                if (alerts().should_post<torrent_paused_alert>())
1691
 
                {
1692
 
                        alerts().post_alert(torrent_paused_alert(get_handle()));
1693
 
                }
1694
 
*/
1695
 
        }
1696
 
 
1697
 
        void torrent::on_save_resume_data(int ret, disk_io_job const& j)
1698
 
        {
1699
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1700
 
 
1701
 
                if (!j.resume_data && alerts().should_post<save_resume_data_failed_alert>())
1702
 
                {
1703
 
                        alerts().post_alert(save_resume_data_failed_alert(get_handle(), j.str));
1704
 
                        return;
1705
 
                }
1706
 
 
1707
 
                if (j.resume_data && alerts().should_post<save_resume_data_alert>())
1708
 
                {
1709
 
                        write_resume_data(*j.resume_data);
1710
 
                        alerts().post_alert(save_resume_data_alert(j.resume_data
1711
 
                                , get_handle()));
1712
 
                }
1713
 
        }
1714
 
 
1715
 
        void torrent::on_file_renamed(int ret, disk_io_job const& j)
1716
 
        {
1717
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1718
 
                
1719
 
                {
1720
 
                        if (ret == 0)
1721
 
                        {
1722
 
                                if (alerts().should_post<file_renamed_alert>())
1723
 
                                        alerts().post_alert(file_renamed_alert(get_handle(), j.str, j.piece));
1724
 
                                m_torrent_file->rename_file(j.piece, j.str);
1725
 
                        }
1726
 
                        else
1727
 
                        {
1728
 
                                if (alerts().should_post<file_rename_failed_alert>())
1729
 
                                        alerts().post_alert(file_rename_failed_alert(get_handle(), j.str, j.piece));
1730
 
                        }
1731
 
                }
1732
 
        }
1733
 
 
1734
 
        void torrent::on_torrent_paused(int ret, disk_io_job const& j)
1735
 
        {
1736
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1737
 
 
1738
 
                if (alerts().should_post<torrent_paused_alert>())
1739
 
                        alerts().post_alert(torrent_paused_alert(get_handle()));
1740
 
        }
1741
 
 
1742
 
        std::string torrent::tracker_login() const
1743
 
        {
1744
 
                if (m_username.empty() && m_password.empty()) return "";
1745
 
                return m_username + ":" + m_password;
1746
 
        }
1747
 
 
1748
 
        void torrent::piece_availability(std::vector<int>& avail) const
1749
 
        {
1750
 
                INVARIANT_CHECK;
1751
 
 
1752
 
                TORRENT_ASSERT(valid_metadata());
1753
 
                if (is_seed())
1754
 
                {
1755
 
                        avail.clear();
1756
 
                        return;
1757
 
                }
1758
 
 
1759
 
                m_picker->get_availability(avail);
1760
 
        }
1761
 
 
1762
 
        void torrent::set_piece_priority(int index, int priority)
1763
 
        {
1764
 
//              INVARIANT_CHECK;
1765
 
 
1766
 
                TORRENT_ASSERT(valid_metadata());
1767
 
                if (is_seed()) return;
1768
 
 
1769
 
                // this call is only valid on torrents with metadata
1770
 
                TORRENT_ASSERT(m_picker.get());
1771
 
                TORRENT_ASSERT(index >= 0);
1772
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1773
 
 
1774
 
                bool was_finished = is_finished();
1775
 
                bool filter_updated = m_picker->set_piece_priority(index, priority);
1776
 
                TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1777
 
                if (filter_updated) update_peer_interest(was_finished);
1778
 
        }
1779
 
 
1780
 
        int torrent::piece_priority(int index) const
1781
 
        {
1782
 
//              INVARIANT_CHECK;
1783
 
 
1784
 
                TORRENT_ASSERT(valid_metadata());
1785
 
                if (is_seed()) return 1;
1786
 
 
1787
 
                // this call is only valid on torrents with metadata
1788
 
                TORRENT_ASSERT(m_picker.get());
1789
 
                TORRENT_ASSERT(index >= 0);
1790
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1791
 
 
1792
 
                return m_picker->piece_priority(index);
1793
 
        }
1794
 
 
1795
 
        void torrent::prioritize_pieces(std::vector<int> const& pieces)
1796
 
        {
1797
 
                INVARIANT_CHECK;
1798
 
 
1799
 
                // this call is only valid on torrents with metadata
1800
 
                TORRENT_ASSERT(valid_metadata());
1801
 
                if (is_seed()) return;
1802
 
 
1803
 
                TORRENT_ASSERT(m_picker.get());
1804
 
 
1805
 
                int index = 0;
1806
 
                bool filter_updated = false;
1807
 
                bool was_finished = is_finished();
1808
 
                for (std::vector<int>::const_iterator i = pieces.begin()
1809
 
                        , end(pieces.end()); i != end; ++i, ++index)
1810
 
                {
1811
 
                        TORRENT_ASSERT(*i >= 0);
1812
 
                        TORRENT_ASSERT(*i <= 7);
1813
 
                        filter_updated |= m_picker->set_piece_priority(index, *i);
1814
 
                        TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1815
 
                }
1816
 
                if (filter_updated) update_peer_interest(was_finished);
1817
 
        }
1818
 
 
1819
 
        void torrent::piece_priorities(std::vector<int>& pieces) const
1820
 
        {
1821
 
                INVARIANT_CHECK;
1822
 
 
1823
 
                // this call is only valid on torrents with metadata
1824
 
                TORRENT_ASSERT(valid_metadata());
1825
 
                if (is_seed())
1826
 
                {
1827
 
                        pieces.clear();
1828
 
                        pieces.resize(m_torrent_file->num_pieces(), 1);
1829
 
                        return;
1830
 
                }
1831
 
 
1832
 
                TORRENT_ASSERT(m_picker.get());
1833
 
                m_picker->piece_priorities(pieces);
1834
 
        }
1835
 
 
1836
 
        namespace
1837
 
        {
1838
 
                void set_if_greater(int& piece_prio, int file_prio)
1839
 
                {
1840
 
                        if (file_prio > piece_prio) piece_prio = file_prio;
1841
 
                }
1842
 
        }
1843
 
 
1844
 
        void torrent::prioritize_files(std::vector<int> const& files)
1845
 
        {
1846
 
                INVARIANT_CHECK;
1847
 
 
1848
 
                // this call is only valid on torrents with metadata
1849
 
                if (!valid_metadata() || is_seed()) return;
1850
 
 
1851
 
                // the bitmask need to have exactly one bit for every file
1852
 
                // in the torrent
1853
 
                TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
1854
 
                
1855
 
                if (m_torrent_file->num_pieces() == 0) return;
1856
 
 
1857
 
                std::copy(files.begin(), files.end(), m_file_priority.begin());
1858
 
                update_piece_priorities();
1859
 
        }
1860
 
 
1861
 
        void torrent::set_file_priority(int index, int prio)
1862
 
        {
1863
 
                INVARIANT_CHECK;
1864
 
                TORRENT_ASSERT(index < m_torrent_file->num_files());
1865
 
                TORRENT_ASSERT(index >= 0);
1866
 
                if (m_file_priority[index] == prio) return;
1867
 
                m_file_priority[index] = prio;
1868
 
                update_piece_priorities();
1869
 
        }
1870
 
        
1871
 
        int torrent::file_priority(int index) const
1872
 
        {
1873
 
                TORRENT_ASSERT(index < m_torrent_file->num_files());
1874
 
                TORRENT_ASSERT(index >= 0);
1875
 
                return m_file_priority[index];
1876
 
        }
1877
 
 
1878
 
        void torrent::file_priorities(std::vector<int>& files) const
1879
 
        {
1880
 
                INVARIANT_CHECK;
1881
 
                files.resize(m_file_priority.size());
1882
 
                std::copy(m_file_priority.begin(), m_file_priority.end(), files.begin());
1883
 
        }
1884
 
 
1885
 
        void torrent::update_piece_priorities()
1886
 
        {
1887
 
                INVARIANT_CHECK;
1888
 
 
1889
 
                if (m_torrent_file->num_pieces() == 0) return;
1890
 
 
1891
 
                size_type position = 0;
1892
 
                int piece_length = m_torrent_file->piece_length();
1893
 
                // initialize the piece priorities to 0, then only allow
1894
 
                // setting higher priorities
1895
 
                std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
1896
 
                for (int i = 0; i < int(m_file_priority.size()); ++i)
1897
 
                {
1898
 
                        size_type start = position;
1899
 
                        size_type size = m_torrent_file->files().at(i).size;
1900
 
                        if (size == 0) continue;
1901
 
                        position += size;
1902
 
                        if (m_file_priority[i] == 0) continue;
1903
 
 
1904
 
                        // mark all pieces of the file with this file's priority
1905
 
                        // but only if the priority is higher than the pieces
1906
 
                        // already set (to avoid problems with overlapping pieces)
1907
 
                        int start_piece = int(start / piece_length);
1908
 
                        int last_piece = int((position - 1) / piece_length);
1909
 
                        TORRENT_ASSERT(last_piece < int(pieces.size()));
1910
 
                        // if one piece spans several files, we might
1911
 
                        // come here several times with the same start_piece, end_piece
1912
 
                        std::for_each(pieces.begin() + start_piece
1913
 
                                , pieces.begin() + last_piece + 1
1914
 
                                , bind(&set_if_greater, _1, m_file_priority[i]));
1915
 
                }
1916
 
                prioritize_pieces(pieces);
1917
 
        }
1918
 
 
1919
 
        // this is called when piece priorities have been updated
1920
 
        // updates the interested flag in peers
1921
 
        void torrent::update_peer_interest(bool was_finished)
1922
 
        {
1923
 
                for (peer_iterator i = begin(); i != end();)
1924
 
                {
1925
 
                        peer_connection* p = *i;
1926
 
                        // update_interest may disconnect the peer and
1927
 
                        // invalidate the iterator
1928
 
                        ++i;
1929
 
                        p->update_interest();
1930
 
                }
1931
 
 
1932
 
                // the torrent just became finished
1933
 
                if (is_finished() && !was_finished)
1934
 
                {
1935
 
                        finished();
1936
 
                }
1937
 
                else if (!is_finished() && was_finished)
1938
 
                {
1939
 
                        // if we used to be finished, but we aren't anymore
1940
 
                        // we may need to connect to peers again
1941
 
                        resume_download();
1942
 
                }
1943
 
        }
1944
 
 
1945
 
        void torrent::filter_piece(int index, bool filter)
1946
 
        {
1947
 
                INVARIANT_CHECK;
1948
 
 
1949
 
                TORRENT_ASSERT(valid_metadata());
1950
 
                if (is_seed()) return;
1951
 
 
1952
 
                // this call is only valid on torrents with metadata
1953
 
                TORRENT_ASSERT(m_picker.get());
1954
 
                TORRENT_ASSERT(index >= 0);
1955
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1956
 
 
1957
 
                bool was_finished = is_finished();
1958
 
                m_picker->set_piece_priority(index, filter ? 1 : 0);
1959
 
                update_peer_interest(was_finished);
1960
 
        }
1961
 
 
1962
 
        void torrent::filter_pieces(std::vector<bool> const& bitmask)
1963
 
        {
1964
 
                INVARIANT_CHECK;
1965
 
 
1966
 
                // this call is only valid on torrents with metadata
1967
 
                TORRENT_ASSERT(valid_metadata());
1968
 
                if (is_seed()) return;
1969
 
 
1970
 
                TORRENT_ASSERT(m_picker.get());
1971
 
 
1972
 
                bool was_finished = is_finished();
1973
 
                int index = 0;
1974
 
                for (std::vector<bool>::const_iterator i = bitmask.begin()
1975
 
                        , end(bitmask.end()); i != end; ++i, ++index)
1976
 
                {
1977
 
                        if ((m_picker->piece_priority(index) == 0) == *i) continue;
1978
 
                        if (*i)
1979
 
                                m_picker->set_piece_priority(index, 0);
1980
 
                        else
1981
 
                                m_picker->set_piece_priority(index, 1);
1982
 
                }
1983
 
                update_peer_interest(was_finished);
1984
 
        }
1985
 
 
1986
 
        bool torrent::is_piece_filtered(int index) const
1987
 
        {
1988
 
                // this call is only valid on torrents with metadata
1989
 
                TORRENT_ASSERT(valid_metadata());
1990
 
                if (is_seed()) return false;
1991
 
                
1992
 
                TORRENT_ASSERT(m_picker.get());
1993
 
                TORRENT_ASSERT(index >= 0);
1994
 
                TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1995
 
 
1996
 
                return m_picker->piece_priority(index) == 0;
1997
 
        }
1998
 
 
1999
 
        void torrent::filtered_pieces(std::vector<bool>& bitmask) const
2000
 
        {
2001
 
                INVARIANT_CHECK;
2002
 
 
2003
 
                // this call is only valid on torrents with metadata
2004
 
                TORRENT_ASSERT(valid_metadata());
2005
 
                if (is_seed())
2006
 
                {
2007
 
                        bitmask.clear();
2008
 
                        bitmask.resize(m_torrent_file->num_pieces(), false);
2009
 
                        return;
2010
 
                }
2011
 
 
2012
 
                TORRENT_ASSERT(m_picker.get());
2013
 
                m_picker->filtered_pieces(bitmask);
2014
 
        }
2015
 
 
2016
 
        void torrent::filter_files(std::vector<bool> const& bitmask)
2017
 
        {
2018
 
                INVARIANT_CHECK;
2019
 
 
2020
 
                // this call is only valid on torrents with metadata
2021
 
                if (!valid_metadata() || is_seed()) return;
2022
 
 
2023
 
                // the bitmask need to have exactly one bit for every file
2024
 
                // in the torrent
2025
 
                TORRENT_ASSERT((int)bitmask.size() == m_torrent_file->num_files());
2026
 
                
2027
 
                size_type position = 0;
2028
 
 
2029
 
                if (m_torrent_file->num_pieces())
2030
 
                {
2031
 
                        int piece_length = m_torrent_file->piece_length();
2032
 
                        // mark all pieces as filtered, then clear the bits for files
2033
 
                        // that should be downloaded
2034
 
                        std::vector<bool> piece_filter(m_torrent_file->num_pieces(), true);
2035
 
                        for (int i = 0; i < (int)bitmask.size(); ++i)
2036
 
                        {
2037
 
                                size_type start = position;
2038
 
                                position += m_torrent_file->files().at(i).size;
2039
 
                                // is the file selected for download?
2040
 
                                if (!bitmask[i])
2041
 
                                {           
2042
 
                                        // mark all pieces of the file as downloadable
2043
 
                                        int start_piece = int(start / piece_length);
2044
 
                                        int last_piece = int(position / piece_length);
2045
 
                                        // if one piece spans several files, we might
2046
 
                                        // come here several times with the same start_piece, end_piece
2047
 
                                        std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
2048
 
                                                + last_piece + 1, false);
2049
 
                                }
2050
 
                        }
2051
 
                        filter_pieces(piece_filter);
2052
 
                }
2053
 
        }
2054
 
 
2055
 
        void torrent::replace_trackers(std::vector<announce_entry> const& urls)
2056
 
        {
2057
 
                m_trackers.clear();
2058
 
                std::remove_copy_if(urls.begin(), urls.end(), back_inserter(m_trackers)
2059
 
                        , boost::bind(&std::string::empty, boost::bind(&announce_entry::url, _1)));
2060
 
 
2061
 
                if (m_currently_trying_tracker >= (int)m_trackers.size())
2062
 
                        m_currently_trying_tracker = (int)m_trackers.size()-1;
2063
 
                m_last_working_tracker = -1;
2064
 
                if (!m_trackers.empty()) start_announcing();
2065
 
                else stop_announcing();
2066
 
        }
2067
 
 
2068
 
        void torrent::choke_peer(peer_connection& c)
2069
 
        {
2070
 
                INVARIANT_CHECK;
2071
 
 
2072
 
                TORRENT_ASSERT(!c.is_choked());
2073
 
                TORRENT_ASSERT(m_num_uploads > 0);
2074
 
                c.send_choke();
2075
 
                --m_num_uploads;
2076
 
        }
2077
 
        
2078
 
        bool torrent::unchoke_peer(peer_connection& c)
2079
 
        {
2080
 
                INVARIANT_CHECK;
2081
 
 
2082
 
                TORRENT_ASSERT(c.is_choked());
2083
 
                if (m_num_uploads >= m_max_uploads) return false;
2084
 
                if (!c.send_unchoke()) return false;
2085
 
                ++m_num_uploads;
2086
 
                return true;
2087
 
        }
2088
 
 
2089
 
        void torrent::cancel_block(piece_block block)
2090
 
        {
2091
 
                INVARIANT_CHECK;
2092
 
 
2093
 
                for (peer_iterator i = m_connections.begin()
2094
 
                        , end(m_connections.end()); i != end; ++i)
2095
 
                {
2096
 
                        (*i)->cancel_request(block);
2097
 
                }
2098
 
        }
2099
 
 
2100
 
        void torrent::remove_peer(peer_connection* p)
2101
 
        {
2102
 
//              INVARIANT_CHECK;
2103
 
 
2104
 
                TORRENT_ASSERT(p != 0);
2105
 
 
2106
 
                peer_iterator i = m_connections.find(p);
2107
 
                if (i == m_connections.end())
2108
 
                {
2109
 
                        TORRENT_ASSERT(false);
2110
 
                        return;
2111
 
                }
2112
 
 
2113
 
                if (ready_for_connections())
2114
 
                {
2115
 
                        TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2116
 
 
2117
 
                        if (p->is_seed())
2118
 
                        {
2119
 
                                if (m_picker.get())
2120
 
                                {
2121
 
                                        m_picker->dec_refcount_all();
2122
 
                                }
2123
 
                        }
2124
 
                        else
2125
 
                        {
2126
 
                                if (m_picker.get())
2127
 
                                {
2128
 
                                        bitfield const& pieces = p->get_bitfield();
2129
 
                                        TORRENT_ASSERT(pieces.count() < int(pieces.size()));
2130
 
                                        m_picker->dec_refcount(pieces);
2131
 
                                }
2132
 
                        }
2133
 
                }
2134
 
 
2135
 
                if (!p->is_choked())
2136
 
                {
2137
 
                        --m_num_uploads;
2138
 
                        m_ses.m_unchoke_time_scaler = 0;
2139
 
                }
2140
 
 
2141
 
                if (p->peer_info_struct() && p->peer_info_struct()->optimistically_unchoked)
2142
 
                {
2143
 
                        m_ses.m_optimistic_unchoke_time_scaler = 0;
2144
 
                }
2145
 
 
2146
 
                m_policy.connection_closed(*p);
2147
 
                p->set_peer_info(0);
2148
 
                TORRENT_ASSERT(i != m_connections.end());
2149
 
                m_connections.erase(i);
2150
 
 
2151
 
                // remove from bandwidth request-queue
2152
 
                for (int c = 0; c < 2; ++c)
2153
 
                {
2154
 
                        for (queue_t::iterator i = m_bandwidth_queue[c].begin()
2155
 
                                , end(m_bandwidth_queue[c].end()); i != end; ++i)
2156
 
                        {
2157
 
                                if (i->peer != p) continue;
2158
 
                                m_bandwidth_queue[c].erase(i);
2159
 
                                break;
2160
 
                        }
2161
 
                }
2162
 
        }
2163
 
 
2164
 
        void torrent::connect_to_url_seed(std::string const& url)
2165
 
        {
2166
 
                INVARIANT_CHECK;
2167
 
 
2168
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2169
 
                (*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
2170
 
#endif
2171
 
 
2172
 
                std::string protocol;
2173
 
                std::string auth;
2174
 
                std::string hostname;
2175
 
                int port;
2176
 
                std::string path;
2177
 
                char const* error;
2178
 
                boost::tie(protocol, auth, hostname, port, path, error)
2179
 
                        = parse_url_components(url);
2180
 
 
2181
 
                if (error)
2182
 
                {
2183
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2184
 
                        (*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n";
2185
 
#endif
2186
 
                        // never try it again
2187
 
                        remove_url_seed(url);
2188
 
                        return;
2189
 
                }
2190
 
                
2191
 
#ifdef TORRENT_USE_OPENSSL
2192
 
                if (protocol != "http" && protocol != "https")
2193
 
#else
2194
 
                if (protocol != "http")
2195
 
#endif
2196
 
                {
2197
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2198
 
                        {
2199
 
                                m_ses.m_alerts.post_alert(
2200
 
                                        url_seed_alert(get_handle(), url, "unknown protocol"));
2201
 
                        }
2202
 
                        // never try it again
2203
 
                        remove_url_seed(url);
2204
 
                        return;
2205
 
                }
2206
 
 
2207
 
                if (hostname.empty())
2208
 
                {
2209
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2210
 
                        {
2211
 
                                m_ses.m_alerts.post_alert(
2212
 
                                        url_seed_alert(get_handle(), url, "invalid hostname"));
2213
 
                        }
2214
 
                        // never try it again
2215
 
                        remove_url_seed(url);
2216
 
                        return;
2217
 
                }
2218
 
 
2219
 
                if (port == 0)
2220
 
                {
2221
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2222
 
                        {
2223
 
                                m_ses.m_alerts.post_alert(
2224
 
                                        url_seed_alert(get_handle(), url, "invalid port"));
2225
 
                        }
2226
 
                        // never try it again
2227
 
                        remove_url_seed(url);
2228
 
                        return;
2229
 
                }
2230
 
 
2231
 
                m_resolving_web_seeds.insert(url);
2232
 
                proxy_settings const& ps = m_ses.web_seed_proxy();
2233
 
                if (ps.type == proxy_settings::http
2234
 
                        || ps.type == proxy_settings::http_pw)
2235
 
                {
2236
 
                        // use proxy
2237
 
                        tcp::resolver::query q(ps.hostname, to_string(ps.port).elems);
2238
 
                        m_host_resolver.async_resolve(q,
2239
 
                                bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url));
2240
 
                }
2241
 
                else
2242
 
                {
2243
 
                        if (m_ses.m_port_filter.access(port) & port_filter::blocked)
2244
 
                        {
2245
 
                                if (m_ses.m_alerts.should_post<url_seed_alert>())
2246
 
                                {
2247
 
                                        m_ses.m_alerts.post_alert(
2248
 
                                                url_seed_alert(get_handle(), url, "port blocked by port-filter"));
2249
 
                                }
2250
 
                                // never try it again
2251
 
                                remove_url_seed(url);
2252
 
                                return;
2253
 
                        }
2254
 
 
2255
 
                        tcp::resolver::query q(hostname, to_string(port).elems);
2256
 
                        m_host_resolver.async_resolve(q,
2257
 
                                bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
2258
 
                                        , tcp::endpoint()));
2259
 
                }
2260
 
 
2261
 
        }
2262
 
 
2263
 
        void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host
2264
 
                , std::string url)
2265
 
        {
2266
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2267
 
 
2268
 
                INVARIANT_CHECK;
2269
 
 
2270
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2271
 
                (*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
2272
 
#endif
2273
 
 
2274
 
                if (m_abort) return;
2275
 
 
2276
 
                if (e || host == tcp::resolver::iterator())
2277
 
                {
2278
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2279
 
                        {
2280
 
                                m_ses.m_alerts.post_alert(
2281
 
                                        url_seed_alert(get_handle(), url, e.message()));
2282
 
                        }
2283
 
 
2284
 
                        // the name lookup failed for the http host. Don't try
2285
 
                        // this host again
2286
 
                        remove_url_seed(url);
2287
 
                        return;
2288
 
                }
2289
 
 
2290
 
                if (m_ses.is_aborted()) return;
2291
 
 
2292
 
                tcp::endpoint a(host->endpoint());
2293
 
 
2294
 
                using boost::tuples::ignore;
2295
 
                std::string hostname;
2296
 
                int port;
2297
 
                char const* error;
2298
 
                boost::tie(ignore, ignore, hostname, port, ignore, error)
2299
 
                        = parse_url_components(url);
2300
 
 
2301
 
                if (error)
2302
 
                {
2303
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2304
 
                        {
2305
 
                                m_ses.m_alerts.post_alert(
2306
 
                                        url_seed_alert(get_handle(), url, error));
2307
 
                        }
2308
 
                        remove_url_seed(url);
2309
 
                        return;
2310
 
                }
2311
 
 
2312
 
                if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2313
 
                {
2314
 
                        if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2315
 
                                m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2316
 
                        return;
2317
 
                }
2318
 
 
2319
 
                tcp::resolver::query q(hostname, to_string(port).elems);
2320
 
                m_host_resolver.async_resolve(q,
2321
 
                        bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a));
2322
 
        }
2323
 
 
2324
 
        void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host
2325
 
                , std::string url, tcp::endpoint proxy)
2326
 
        {
2327
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2328
 
 
2329
 
                INVARIANT_CHECK;
2330
 
 
2331
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2332
 
                (*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
2333
 
#endif
2334
 
 
2335
 
                if (m_abort) return;
2336
 
 
2337
 
                std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
2338
 
                if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
2339
 
 
2340
 
                if (e || host == tcp::resolver::iterator())
2341
 
                {
2342
 
                        if (m_ses.m_alerts.should_post<url_seed_alert>())
2343
 
                        {
2344
 
                                std::stringstream msg;
2345
 
                                msg << "HTTP seed hostname lookup failed: " << e.message();
2346
 
                                m_ses.m_alerts.post_alert(
2347
 
                                        url_seed_alert(get_handle(), url, msg.str()));
2348
 
                        }
2349
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2350
 
                        (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
2351
 
#endif
2352
 
 
2353
 
                        // the name lookup failed for the http host. Don't try
2354
 
                        // this host again
2355
 
                        remove_url_seed(url);
2356
 
                        return;
2357
 
                }
2358
 
 
2359
 
                if (m_ses.is_aborted()) return;
2360
 
 
2361
 
                tcp::endpoint a(host->endpoint());
2362
 
 
2363
 
                if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2364
 
                {
2365
 
                        if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2366
 
                                m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2367
 
                        return;
2368
 
                }
2369
 
                
2370
 
                boost::shared_ptr<socket_type> s(new (std::nothrow) socket_type(m_ses.m_io_service));
2371
 
                if (!s) return;
2372
 
        
2373
 
                bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
2374
 
                (void)ret;
2375
 
                TORRENT_ASSERT(ret);
2376
 
 
2377
 
                if (m_ses.web_seed_proxy().type == proxy_settings::http
2378
 
                        || m_ses.web_seed_proxy().type == proxy_settings::http_pw)
2379
 
                {
2380
 
                        // the web seed connection will talk immediately to
2381
 
                        // the proxy, without requiring CONNECT support
2382
 
                        s->get<http_stream>().set_no_connect(true);
2383
 
                }
2384
 
 
2385
 
                boost::intrusive_ptr<peer_connection> c(new (std::nothrow) web_peer_connection(
2386
 
                        m_ses, shared_from_this(), s, a, url, 0));
2387
 
                if (!c) return;
2388
 
                        
2389
 
#ifdef TORRENT_DEBUG
2390
 
                c->m_in_constructor = false;
2391
 
#endif
2392
 
 
2393
 
#ifndef TORRENT_DISABLE_EXTENSIONS
2394
 
                for (extension_list_t::iterator i = m_extensions.begin()
2395
 
                        , end(m_extensions.end()); i != end; ++i)
2396
 
                {
2397
 
                        boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2398
 
                        if (pp) c->add_extension(pp);
2399
 
                }
2400
 
#endif
2401
 
 
2402
 
#ifndef BOOST_NO_EXCEPTIONS
2403
 
                try
2404
 
                {
2405
 
#endif
2406
 
                        // add the newly connected peer to this torrent's peer list
2407
 
                        m_connections.insert(boost::get_pointer(c));
2408
 
                        m_ses.m_connections.insert(c);
2409
 
                        c->start();
2410
 
 
2411
 
                        m_ses.m_half_open.enqueue(
2412
 
                                bind(&peer_connection::connect, c, _1)
2413
 
                                , bind(&peer_connection::timed_out, c)
2414
 
                                , seconds(settings().peer_connect_timeout));
2415
 
#ifndef BOOST_NO_EXCEPTIONS
2416
 
                }
2417
 
                catch (std::exception& e)
2418
 
                {
2419
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2420
 
                        (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
2421
 
#endif
2422
 
                        c->disconnect(e.what(), 1);
2423
 
                }
2424
 
#endif
2425
 
        }
2426
 
 
2427
 
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2428
 
        namespace
2429
 
        {
2430
 
                unsigned long swap_bytes(unsigned long a)
2431
 
                {
2432
 
                        return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | ((a & 0xff) << 24);
2433
 
                }
2434
 
        }
2435
 
        
2436
 
        void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
2437
 
        {
2438
 
                if (m_resolving_country
2439
 
                        || p->has_country()
2440
 
                        || p->is_connecting()
2441
 
                        || p->is_queued()
2442
 
                        || p->in_handshake()
2443
 
                        || p->remote().address().is_v6()) return;
2444
 
 
2445
 
                asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong()));
2446
 
                error_code ec;
2447
 
                tcp::resolver::query q(reversed.to_string(ec) + ".zz.countries.nerd.dk", "0");
2448
 
                if (ec)
2449
 
                {
2450
 
                        p->set_country("!!");
2451
 
                        return;
2452
 
                }
2453
 
                m_resolving_country = true;
2454
 
                m_host_resolver.async_resolve(q,
2455
 
                        bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p));
2456
 
        }
2457
 
 
2458
 
        namespace
2459
 
        {
2460
 
                struct country_entry
2461
 
                {
2462
 
                        int code;
2463
 
                        char const* name;
2464
 
                };
2465
 
        }
2466
 
 
2467
 
        void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i
2468
 
                , intrusive_ptr<peer_connection> p) const
2469
 
        {
2470
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2471
 
 
2472
 
                INVARIANT_CHECK;
2473
 
                
2474
 
                m_resolving_country = false;
2475
 
 
2476
 
                if (m_abort) return;
2477
 
 
2478
 
                // must be ordered in increasing order
2479
 
                static const country_entry country_map[] =
2480
 
                {
2481
 
                          {  4,  "AF"}, {  8,  "AL"}, { 10,  "AQ"}, { 12,  "DZ"}, { 16,  "AS"}
2482
 
                        , { 20,  "AD"}, { 24,  "AO"}, { 28,  "AG"}, { 31,  "AZ"}, { 32,  "AR"}
2483
 
                        , { 36,  "AU"}, { 40,  "AT"}, { 44,  "BS"}, { 48,  "BH"}, { 50,  "BD"}
2484
 
                        , { 51,  "AM"}, { 52,  "BB"}, { 56,  "BE"}, { 60,  "BM"}, { 64,  "BT"}
2485
 
                        , { 68,  "BO"}, { 70,  "BA"}, { 72,  "BW"}, { 74,  "BV"}, { 76,  "BR"}
2486
 
                        , { 84,  "BZ"}, { 86,  "IO"}, { 90,  "SB"}, { 92,  "VG"}, { 96,  "BN"}
2487
 
                        , {100,  "BG"}, {104,  "MM"}, {108,  "BI"}, {112,  "BY"}, {116,  "KH"}
2488
 
                        , {120,  "CM"}, {124,  "CA"}, {132,  "CV"}, {136,  "KY"}, {140,  "CF"}
2489
 
                        , {144,  "LK"}, {148,  "TD"}, {152,  "CL"}, {156,  "CN"}, {158,  "TW"}
2490
 
                        , {162,  "CX"}, {166,  "CC"}, {170,  "CO"}, {174,  "KM"}, {175,  "YT"}
2491
 
                        , {178,  "CG"}, {180,  "CD"}, {184,  "CK"}, {188,  "CR"}, {191,  "HR"}
2492
 
                        , {192,  "CU"}, {203,  "CZ"}, {204,  "BJ"}, {208,  "DK"}, {212,  "DM"}
2493
 
                        , {214,  "DO"}, {218,  "EC"}, {222,  "SV"}, {226,  "GQ"}, {231,  "ET"}
2494
 
                        , {232,  "ER"}, {233,  "EE"}, {234,  "FO"}, {238,  "FK"}, {239,  "GS"}
2495
 
                        , {242,  "FJ"}, {246,  "FI"}, {248,  "AX"}, {250,  "FR"}, {254,  "GF"}
2496
 
                        , {258,  "PF"}, {260,  "TF"}, {262,  "DJ"}, {266,  "GA"}, {268,  "GE"}
2497
 
                        , {270,  "GM"}, {275,  "PS"}, {276,  "DE"}, {288,  "GH"}, {292,  "GI"}
2498
 
                        , {296,  "KI"}, {300,  "GR"}, {304,  "GL"}, {308,  "GD"}, {312,  "GP"}
2499
 
                        , {316,  "GU"}, {320,  "GT"}, {324,  "GN"}, {328,  "GY"}, {332,  "HT"}
2500
 
                        , {334,  "HM"}, {336,  "VA"}, {340,  "HN"}, {344,  "HK"}, {348,  "HU"}
2501
 
                        , {352,  "IS"}, {356,  "IN"}, {360,  "ID"}, {364,  "IR"}, {368,  "IQ"}
2502
 
                        , {372,  "IE"}, {376,  "IL"}, {380,  "IT"}, {384,  "CI"}, {388,  "JM"}
2503
 
                        , {392,  "JP"}, {398,  "KZ"}, {400,  "JO"}, {404,  "KE"}, {408,  "KP"}
2504
 
                        , {410,  "KR"}, {414,  "KW"}, {417,  "KG"}, {418,  "LA"}, {422,  "LB"}
2505
 
                        , {426,  "LS"}, {428,  "LV"}, {430,  "LR"}, {434,  "LY"}, {438,  "LI"}
2506
 
                        , {440,  "LT"}, {442,  "LU"}, {446,  "MO"}, {450,  "MG"}, {454,  "MW"}
2507
 
                        , {458,  "MY"}, {462,  "MV"}, {466,  "ML"}, {470,  "MT"}, {474,  "MQ"}
2508
 
                        , {478,  "MR"}, {480,  "MU"}, {484,  "MX"}, {492,  "MC"}, {496,  "MN"}
2509
 
                        , {498,  "MD"}, {500,  "MS"}, {504,  "MA"}, {508,  "MZ"}, {512,  "OM"}
2510
 
                        , {516,  "NA"}, {520,  "NR"}, {524,  "NP"}, {528,  "NL"}, {530,  "AN"}
2511
 
                        , {533,  "AW"}, {540,  "NC"}, {548,  "VU"}, {554,  "NZ"}, {558,  "NI"}
2512
 
                        , {562,  "NE"}, {566,  "NG"}, {570,  "NU"}, {574,  "NF"}, {578,  "NO"}
2513
 
                        , {580,  "MP"}, {581,  "UM"}, {583,  "FM"}, {584,  "MH"}, {585,  "PW"}
2514
 
                        , {586,  "PK"}, {591,  "PA"}, {598,  "PG"}, {600,  "PY"}, {604,  "PE"}
2515
 
                        , {608,  "PH"}, {612,  "PN"}, {616,  "PL"}, {620,  "PT"}, {624,  "GW"}
2516
 
                        , {626,  "TL"}, {630,  "PR"}, {634,  "QA"}, {634,  "QA"}, {638,  "RE"}
2517
 
                        , {642,  "RO"}, {643,  "RU"}, {646,  "RW"}, {654,  "SH"}, {659,  "KN"}
2518
 
                        , {660,  "AI"}, {662,  "LC"}, {666,  "PM"}, {670,  "VC"}, {674,  "SM"}
2519
 
                        , {678,  "ST"}, {682,  "SA"}, {686,  "SN"}, {690,  "SC"}, {694,  "SL"}
2520
 
                        , {702,  "SG"}, {703,  "SK"}, {704,  "VN"}, {705,  "SI"}, {706,  "SO"}
2521
 
                        , {710,  "ZA"}, {716,  "ZW"}, {724,  "ES"}, {732,  "EH"}, {736,  "SD"}
2522
 
                        , {740,  "SR"}, {744,  "SJ"}, {748,  "SZ"}, {752,  "SE"}, {756,  "CH"}
2523
 
                        , {760,  "SY"}, {762,  "TJ"}, {764,  "TH"}, {768,  "TG"}, {772,  "TK"}
2524
 
                        , {776,  "TO"}, {780,  "TT"}, {784,  "AE"}, {788,  "TN"}, {792,  "TR"}
2525
 
                        , {795,  "TM"}, {796,  "TC"}, {798,  "TV"}, {800,  "UG"}, {804,  "UA"}
2526
 
                        , {807,  "MK"}, {818,  "EG"}, {826,  "GB"}, {834,  "TZ"}, {840,  "US"}
2527
 
                        , {850,  "VI"}, {854,  "BF"}, {858,  "UY"}, {860,  "UZ"}, {862,  "VE"}
2528
 
                        , {876,  "WF"}, {882,  "WS"}, {887,  "YE"}, {891,  "CS"}, {894,  "ZM"}
2529
 
                };
2530
 
 
2531
 
                if (error || i == tcp::resolver::iterator())
2532
 
                {
2533
 
                        // this is used to indicate that we shouldn't
2534
 
                        // try to resolve it again
2535
 
                        p->set_country("--");
2536
 
                        return;
2537
 
                }
2538
 
 
2539
 
                while (i != tcp::resolver::iterator()
2540
 
                        && !i->endpoint().address().is_v4()) ++i;
2541
 
                if (i != tcp::resolver::iterator())
2542
 
                {
2543
 
                        // country is an ISO 3166 country code
2544
 
                        int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
2545
 
                        
2546
 
                        // look up the country code in the map
2547
 
                        const int size = sizeof(country_map)/sizeof(country_map[0]);
2548
 
                        country_entry tmp = {country, ""};
2549
 
                        country_entry const* i =
2550
 
                                std::lower_bound(country_map, country_map + size, tmp
2551
 
                                        , bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
2552
 
                        if (i == country_map + size
2553
 
                                || i->code != country)
2554
 
                        {
2555
 
                                // unknown country!
2556
 
                                p->set_country("!!");
2557
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2558
 
                                (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
2559
 
#endif
2560
 
                                return;
2561
 
                        }
2562
 
                        
2563
 
                        p->set_country(i->name);
2564
 
                }
2565
 
        }
2566
 
#endif
2567
 
 
2568
 
        void torrent::read_resume_data(lazy_entry const& rd)
2569
 
        {
2570
 
                m_total_uploaded = rd.dict_find_int_value("total_uploaded");
2571
 
                m_total_downloaded = rd.dict_find_int_value("total_downloaded");
2572
 
                m_active_time = seconds(rd.dict_find_int_value("active_time"));
2573
 
                m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
2574
 
                m_complete = rd.dict_find_int_value("num_seeds", -1);
2575
 
                m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
2576
 
                set_upload_limit(rd.dict_find_int_value("upload_rate_limit", -1));
2577
 
                set_download_limit(rd.dict_find_int_value("download_rate_limit", -1));
2578
 
                set_max_connections(rd.dict_find_int_value("max_connections", -1));
2579
 
                set_max_uploads(rd.dict_find_int_value("max_uploads", -1));
2580
 
 
2581
 
                lazy_entry const* file_priority = rd.dict_find_list("file_priority");
2582
 
                if (file_priority && file_priority->list_size()
2583
 
                        == m_torrent_file->num_files())
2584
 
                {
2585
 
                        for (int i = 0; i < file_priority->list_size(); ++i)
2586
 
                                m_file_priority[i] = file_priority->list_int_value_at(i, 1);
2587
 
                        update_piece_priorities();
2588
 
                }
2589
 
                lazy_entry const* piece_priority = rd.dict_find_string("piece_priority");
2590
 
                if (piece_priority && piece_priority->string_length()
2591
 
                        == m_torrent_file->num_pieces())
2592
 
                {
2593
 
                        char const* p = piece_priority->string_ptr();
2594
 
                        for (int i = 0; i < piece_priority->string_length(); ++i)
2595
 
                                m_picker->set_piece_priority(i, p[i]);
2596
 
                }
2597
 
 
2598
 
                int auto_managed_ = rd.dict_find_int_value("auto_managed", -1);
2599
 
                if (auto_managed_ != -1) m_auto_managed = auto_managed_;
2600
 
 
2601
 
                int sequential_ = rd.dict_find_int_value("sequential_download", -1);
2602
 
                if (sequential_ != -1) set_sequential_download(sequential_);
2603
 
 
2604
 
                int paused_ = rd.dict_find_int_value("paused", -1);
2605
 
                if (paused_ != -1) m_paused = paused_;
2606
 
 
2607
 
                lazy_entry const* trackers = rd.dict_find_list("trackers");
2608
 
                if (trackers)
2609
 
                {
2610
 
                        int tier = 0;
2611
 
                        for (int i = 0; i < trackers->list_size(); ++i)
2612
 
                        {
2613
 
                                lazy_entry const* tier_list = trackers->list_at(i);
2614
 
                                if (tier_list == 0 || tier_list->type() != lazy_entry::list_t)
2615
 
                                        continue;
2616
 
                                for (int j = 0; j < tier_list->list_size(); ++j)
2617
 
                                {
2618
 
                                        announce_entry e(tier_list->list_string_value_at(j));
2619
 
                                        if (std::find_if(m_trackers.begin(), m_trackers.end()
2620
 
                                                , boost::bind(&announce_entry::url, _1) == e.url) != m_trackers.end())
2621
 
                                                continue;
2622
 
                                        e.tier = tier;
2623
 
                                        m_trackers.push_back(e);
2624
 
                                }
2625
 
                                ++tier;
2626
 
                        }
2627
 
                        std::sort(m_trackers.begin(), m_trackers.end(), boost::bind(&announce_entry::tier, _1)
2628
 
                                < boost::bind(&announce_entry::tier, _2));
2629
 
                }
2630
 
 
2631
 
                lazy_entry const* mapped_files = rd.dict_find_list("mapped_files");
2632
 
                if (mapped_files && mapped_files->list_size() == m_torrent_file->num_files())
2633
 
                {
2634
 
                        for (int i = 0; i < m_torrent_file->num_files(); ++i)
2635
 
                        {
2636
 
                                std::string new_filename = mapped_files->list_string_value_at(i);
2637
 
                                if (new_filename.empty()) continue;
2638
 
                                m_torrent_file->rename_file(i, new_filename);
2639
 
                        }
2640
 
                }
2641
 
 
2642
 
                lazy_entry const* url_list = rd.dict_find_list("url-list");
2643
 
                if (url_list)
2644
 
                {
2645
 
                        for (int i = 0; i < url_list->list_size(); ++i)
2646
 
                        {
2647
 
                                std::string url = url_list->list_string_value_at(i);
2648
 
                                if (url.empty()) continue;
2649
 
                                m_web_seeds.insert(url);
2650
 
                        }
2651
 
                }
2652
 
        }
2653
 
        
2654
 
        void torrent::write_resume_data(entry& ret) const
2655
 
        {
2656
 
                ret["file-format"] = "libtorrent resume file";
2657
 
                ret["file-version"] = 1;
2658
 
                ret["libtorrent-version"] = LIBTORRENT_VERSION;
2659
 
 
2660
 
                ret["total_uploaded"] = m_total_uploaded;
2661
 
                ret["total_downloaded"] = m_total_downloaded;
2662
 
 
2663
 
                ret["active_time"] = total_seconds(m_active_time);
2664
 
                ret["seeding_time"] = total_seconds(m_seeding_time);
2665
 
 
2666
 
                int seeds = 0;
2667
 
                int downloaders = 0;
2668
 
                if (m_complete >= 0) seeds = m_complete;
2669
 
                else seeds = m_policy.num_seeds();
2670
 
                if (m_incomplete >= 0) downloaders = m_incomplete;
2671
 
                else downloaders = m_policy.num_peers() - m_policy.num_seeds();
2672
 
 
2673
 
                ret["num_seeds"] = seeds;
2674
 
                ret["num_downloaders"] = downloaders;
2675
 
 
2676
 
                ret["sequential_download"] = m_sequential_download;
2677
 
                
2678
 
                const sha1_hash& info_hash = torrent_file().info_hash();
2679
 
                ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
2680
 
 
2681
 
                // blocks per piece
2682
 
                int num_blocks_per_piece =
2683
 
                        static_cast<int>(torrent_file().piece_length()) / block_size();
2684
 
                ret["blocks per piece"] = num_blocks_per_piece;
2685
 
 
2686
 
                // if this torrent is a seed, we won't have a piece picker
2687
 
                // and there will be no half-finished pieces.
2688
 
                if (!is_seed())
2689
 
                {
2690
 
                        const std::vector<piece_picker::downloading_piece>& q
2691
 
                                = m_picker->get_download_queue();
2692
 
 
2693
 
                        // unfinished pieces
2694
 
                        ret["unfinished"] = entry::list_type();
2695
 
                        entry::list_type& up = ret["unfinished"].list();
2696
 
 
2697
 
                        // info for each unfinished piece
2698
 
                        for (std::vector<piece_picker::downloading_piece>::const_iterator i
2699
 
                                = q.begin(); i != q.end(); ++i)
2700
 
                        {
2701
 
                                if (i->finished == 0) continue;
2702
 
 
2703
 
                                entry piece_struct(entry::dictionary_t);
2704
 
 
2705
 
                                // the unfinished piece's index
2706
 
                                piece_struct["piece"] = i->index;
2707
 
 
2708
 
                                std::string bitmask;
2709
 
                                const int num_bitmask_bytes
2710
 
                                        = (std::max)(num_blocks_per_piece / 8, 1);
2711
 
 
2712
 
                                for (int j = 0; j < num_bitmask_bytes; ++j)
2713
 
                                {
2714
 
                                        unsigned char v = 0;
2715
 
                                        int bits = (std::min)(num_blocks_per_piece - j*8, 8);
2716
 
                                        for (int k = 0; k < bits; ++k)
2717
 
                                                v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
2718
 
                                                ? (1 << k) : 0;
2719
 
                                        bitmask.insert(bitmask.end(), v);
2720
 
                                        TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
2721
 
                                }
2722
 
                                piece_struct["bitmask"] = bitmask;
2723
 
                                // push the struct onto the unfinished-piece list
2724
 
                                up.push_back(piece_struct);
2725
 
                        }
2726
 
                }
2727
 
 
2728
 
                // save trackers
2729
 
                if (!m_trackers.empty())
2730
 
                {
2731
 
                        entry::list_type& tr_list = ret["trackers"].list();
2732
 
                        tr_list.push_back(entry::list_type());
2733
 
                        int tier = 0;
2734
 
                        for (std::vector<announce_entry>::const_iterator i = m_trackers.begin()
2735
 
                                , end(m_trackers.end()); i != end; ++i)
2736
 
                        {
2737
 
                                if (i->tier == tier)
2738
 
                                {
2739
 
                                        tr_list.back().list().push_back(i->url);
2740
 
                                }
2741
 
                                else
2742
 
                                {
2743
 
                                        tr_list.push_back(entry::list_t);
2744
 
                                        tr_list.back().list().push_back(i->url);
2745
 
                                        tier = i->tier;
2746
 
                                }
2747
 
                        }
2748
 
                }
2749
 
 
2750
 
                // save web seeds
2751
 
                if (!m_web_seeds.empty())
2752
 
                {
2753
 
                        entry::list_type& url_list = ret["url-list"].list();
2754
 
                        for (std::set<std::string>::const_iterator i = m_web_seeds.begin()
2755
 
                                , end(m_web_seeds.end()); i != end; ++i)
2756
 
                        {
2757
 
                                url_list.push_back(*i);
2758
 
                        }
2759
 
                }
2760
 
 
2761
 
                // write have bitmask
2762
 
                entry::string_type& pieces = ret["pieces"].string();
2763
 
                pieces.resize(m_torrent_file->num_pieces());
2764
 
                if (is_seed())
2765
 
                {
2766
 
                        std::memset(&pieces[0], 1, pieces.size());
2767
 
                }
2768
 
                else
2769
 
                {
2770
 
                        for (int i = 0, end(pieces.size()); i < end; ++i)
2771
 
                                pieces[i] = m_picker->have_piece(i) ? 1 : 0;
2772
 
                }
2773
 
 
2774
 
                // write renamed files
2775
 
                if (&m_torrent_file->files() != &m_torrent_file->orig_files())
2776
 
                {
2777
 
                        entry::list_type& fl = ret["mapped_files"].list();
2778
 
                        for (torrent_info::file_iterator i = m_torrent_file->begin_files()
2779
 
                                , end(m_torrent_file->end_files()); i != end; ++i)
2780
 
                        {
2781
 
                                fl.push_back(i->path.string());
2782
 
                        }
2783
 
                }
2784
 
 
2785
 
                // write local peers
2786
 
 
2787
 
                entry::list_type& peer_list = ret["peers"].list();
2788
 
                entry::list_type& banned_peer_list = ret["banned_peers"].list();
2789
 
                
2790
 
                int max_failcount = m_ses.m_settings.max_failcount;
2791
 
 
2792
 
                for (policy::const_iterator i = m_policy.begin_peer()
2793
 
                        , end(m_policy.end_peer()); i != end; ++i)
2794
 
                {
2795
 
                        error_code ec;
2796
 
                        if (i->second.banned)
2797
 
                        {
2798
 
                                entry peer(entry::dictionary_t);
2799
 
                                peer["ip"] = i->second.addr.to_string(ec);
2800
 
                                if (ec) continue;
2801
 
                                peer["port"] = i->second.port;
2802
 
                                banned_peer_list.push_back(peer);
2803
 
                                continue;
2804
 
                        }
2805
 
                        // we cannot save remote connection
2806
 
                        // since we don't know their listen port
2807
 
                        // unless they gave us their listen port
2808
 
                        // through the extension handshake
2809
 
                        // so, if the peer is not connectable (i.e. we
2810
 
                        // don't know its listen port) or if it has
2811
 
                        // been banned, don't save it.
2812
 
                        if (i->second.type == policy::peer::not_connectable) continue;
2813
 
 
2814
 
                        // don't save peers that doesn't work
2815
 
                        if (i->second.failcount >= max_failcount) continue;
2816
 
 
2817
 
                        entry peer(entry::dictionary_t);
2818
 
                        peer["ip"] = i->second.addr.to_string(ec);
2819
 
                        if (ec) continue;
2820
 
                        peer["port"] = i->second.port;
2821
 
                        peer_list.push_back(peer);
2822
 
                }
2823
 
 
2824
 
                ret["upload_rate_limit"] = upload_limit();
2825
 
                ret["download_rate_limit"] = download_limit();
2826
 
                ret["max_connections"] = max_connections();
2827
 
                ret["max_uploads"] = max_uploads();
2828
 
                ret["paused"] = m_paused;
2829
 
                ret["auto_managed"] = m_auto_managed;
2830
 
 
2831
 
                // write piece priorities
2832
 
                entry::string_type& piece_priority = ret["piece_priority"].string();
2833
 
                piece_priority.resize(m_torrent_file->num_pieces());
2834
 
                if (is_seed())
2835
 
                {
2836
 
                        std::memset(&piece_priority[0], 1, pieces.size());
2837
 
                }
2838
 
                else
2839
 
                {
2840
 
                        for (int i = 0, end(piece_priority.size()); i < end; ++i)
2841
 
                                piece_priority[i] = m_picker->piece_priority(i);
2842
 
                }
2843
 
 
2844
 
                // write file priorities
2845
 
                entry::list_type& file_priority = ret["file_priority"].list();
2846
 
                file_priority.clear();
2847
 
                for (int i = 0, end(m_file_priority.size()); i < end; ++i)
2848
 
                        file_priority.push_back(m_file_priority[i]);
2849
 
 
2850
 
        }
2851
 
 
2852
 
        void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
2853
 
        {
2854
 
                v.clear();
2855
 
                v.reserve(m_policy.num_peers());
2856
 
                for (policy::const_iterator i = m_policy.begin_peer();
2857
 
                        i != m_policy.end_peer(); ++i)
2858
 
                {
2859
 
                        peer_list_entry e;
2860
 
                        e.ip = i->second.ip();
2861
 
                        e.flags = i->second.banned ? peer_list_entry::banned : 0;
2862
 
                        e.failcount = i->second.failcount;
2863
 
                        e.source = i->second.source;
2864
 
                        v.push_back(e);
2865
 
                }
2866
 
        }
2867
 
 
2868
 
        void torrent::get_peer_info(std::vector<peer_info>& v)
2869
 
        {
2870
 
                v.clear();
2871
 
                for (peer_iterator i = begin();
2872
 
                        i != end(); ++i)
2873
 
                {
2874
 
                        peer_connection* peer = *i;
2875
 
 
2876
 
                        // incoming peers that haven't finished the handshake should
2877
 
                        // not be included in this list
2878
 
                        if (peer->associated_torrent().expired()) continue;
2879
 
 
2880
 
                        v.push_back(peer_info());
2881
 
                        peer_info& p = v.back();
2882
 
                        
2883
 
                        peer->get_peer_info(p);
2884
 
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2885
 
                        if (resolving_countries())
2886
 
                                resolve_peer_country(intrusive_ptr<peer_connection>(peer));
2887
 
#endif
2888
 
                }
2889
 
        }
2890
 
 
2891
 
        void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
2892
 
        {
2893
 
                queue.clear();
2894
 
                if (!valid_metadata() || is_seed()) return;
2895
 
                piece_picker const& p = picker();
2896
 
                std::vector<piece_picker::downloading_piece> const& q
2897
 
                        = p.get_download_queue();
2898
 
 
2899
 
                for (std::vector<piece_picker::downloading_piece>::const_iterator i
2900
 
                        = q.begin(); i != q.end(); ++i)
2901
 
                {
2902
 
                        partial_piece_info pi;
2903
 
                        pi.piece_state = (partial_piece_info::state_t)i->state;
2904
 
                        pi.blocks_in_piece = p.blocks_in_piece(i->index);
2905
 
                        pi.finished = (int)i->finished;
2906
 
                        pi.writing = (int)i->writing;
2907
 
                        pi.requested = (int)i->requested;
2908
 
                        int piece_size = int(torrent_file().piece_size(i->index));
2909
 
                        int num_blocks = (std::min)(pi.blocks_in_piece, int(partial_piece_info::max_blocks_per_piece));
2910
 
                        for (int j = 0; j < num_blocks; ++j)
2911
 
                        {
2912
 
                                block_info& bi = pi.blocks[j];
2913
 
                                bi.state = i->info[j].state;
2914
 
                                bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
2915
 
                                        : piece_size - (j * m_block_size);
2916
 
                                bool complete = bi.state == block_info::writing
2917
 
                                        || bi.state == block_info::finished;
2918
 
                                if (i->info[j].peer == 0)
2919
 
                                {
2920
 
                                        bi.peer = tcp::endpoint();
2921
 
                                        bi.bytes_progress = complete ? bi.block_size : 0;
2922
 
                                }
2923
 
                                else
2924
 
                                {
2925
 
                                        policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
2926
 
                                        if (p->connection)
2927
 
                                        {
2928
 
                                                bi.peer = p->connection->remote();
2929
 
                                                if (bi.state == block_info::requested)
2930
 
                                                {
2931
 
                                                        boost::optional<piece_block_progress> pbp
2932
 
                                                                = p->connection->downloading_piece_progress();
2933
 
                                                        if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
2934
 
                                                        {
2935
 
                                                                bi.bytes_progress = pbp->bytes_downloaded;
2936
 
                                                                TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
2937
 
                                                        }
2938
 
                                                        else
2939
 
                                                        {
2940
 
                                                                bi.bytes_progress = 0;
2941
 
                                                        }
2942
 
                                                }
2943
 
                                                else
2944
 
                                                {
2945
 
                                                        bi.bytes_progress = complete ? bi.block_size : 0;
2946
 
                                                }
2947
 
                                        }
2948
 
                                        else
2949
 
                                        {
2950
 
                                                bi.peer = p->ip();
2951
 
                                                bi.bytes_progress = complete ? bi.block_size : 0;
2952
 
                                        }
2953
 
                                }
2954
 
 
2955
 
                                pi.blocks[j].num_peers = i->info[j].num_peers;
2956
 
                        }
2957
 
                        pi.piece_index = i->index;
2958
 
                        queue.push_back(pi);
2959
 
                }
2960
 
        
2961
 
        }
2962
 
        
2963
 
        bool torrent::connect_to_peer(policy::peer* peerinfo)
2964
 
        {
2965
 
                INVARIANT_CHECK;
2966
 
 
2967
 
                TORRENT_ASSERT(peerinfo);
2968
 
                TORRENT_ASSERT(peerinfo->connection == 0);
2969
 
 
2970
 
                peerinfo->connected = time_now();
2971
 
#ifdef TORRENT_DEBUG
2972
 
                // this asserts that we don't have duplicates in the policy's peer list
2973
 
                peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
2974
 
                        , bind(&peer_connection::remote, _1) == peerinfo->ip());
2975
 
                TORRENT_ASSERT(i_ == m_connections.end()
2976
 
                        || dynamic_cast<bt_peer_connection*>(*i_) == 0);
2977
 
#endif
2978
 
 
2979
 
                TORRENT_ASSERT(want_more_peers());
2980
 
                TORRENT_ASSERT(m_ses.num_connections() < m_ses.max_connections());
2981
 
 
2982
 
                tcp::endpoint a(peerinfo->ip());
2983
 
                TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->addr) & ip_filter::blocked) == 0);
2984
 
 
2985
 
                boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
2986
 
 
2987
 
                bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
2988
 
                (void)ret;
2989
 
                TORRENT_ASSERT(ret);
2990
 
 
2991
 
                boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
2992
 
                        m_ses, shared_from_this(), s, a, peerinfo));
2993
 
 
2994
 
#ifdef TORRENT_DEBUG
2995
 
                c->m_in_constructor = false;
2996
 
#endif
2997
 
 
2998
 
                c->add_stat(peerinfo->prev_amount_download, peerinfo->prev_amount_upload);
2999
 
                peerinfo->prev_amount_download = 0;
3000
 
                peerinfo->prev_amount_upload = 0;
3001
 
 
3002
 
#ifndef TORRENT_DISABLE_EXTENSIONS
3003
 
                for (extension_list_t::iterator i = m_extensions.begin()
3004
 
                        , end(m_extensions.end()); i != end; ++i)
3005
 
                {
3006
 
#ifndef BOOST_NO_EXCEPTIONS
3007
 
                        try {
3008
 
#endif
3009
 
                                boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
3010
 
                                if (pp) c->add_extension(pp);
3011
 
#ifndef BOOST_NO_EXCEPTIONS
3012
 
                        } catch (std::exception&) {}
3013
 
#endif
3014
 
                }
3015
 
#endif
3016
 
 
3017
 
                // add the newly connected peer to this torrent's peer list
3018
 
                m_connections.insert(boost::get_pointer(c));
3019
 
                m_ses.m_connections.insert(c);
3020
 
                peerinfo->connection = c.get();
3021
 
                c->start();
3022
 
 
3023
 
                int timeout = settings().peer_connect_timeout;
3024
 
                if (peerinfo) timeout += 3 * peerinfo->failcount;
3025
 
 
3026
 
#ifndef BOOST_NO_EXCEPTIONS
3027
 
                try
3028
 
                {
3029
 
#endif
3030
 
                        m_ses.m_half_open.enqueue(
3031
 
                                bind(&peer_connection::connect, c, _1)
3032
 
                                , bind(&peer_connection::timed_out, c)
3033
 
                                , seconds(timeout));
3034
 
#ifndef BOOST_NO_EXCEPTIONS
3035
 
                }
3036
 
                catch (std::exception& e)
3037
 
                {
3038
 
                        std::set<peer_connection*>::iterator i
3039
 
                                = m_connections.find(boost::get_pointer(c));
3040
 
                        if (i != m_connections.end()) m_connections.erase(i);
3041
 
                        c->disconnect(e.what());
3042
 
                        return false;
3043
 
                }
3044
 
#endif
3045
 
 
3046
 
                return peerinfo->connection;
3047
 
        }
3048
 
 
3049
 
        bool torrent::set_metadata(lazy_entry const& metadata, std::string& error)
3050
 
        {
3051
 
                INVARIANT_CHECK;
3052
 
 
3053
 
                TORRENT_ASSERT(!m_torrent_file->is_valid());
3054
 
                if (!m_torrent_file->parse_info_section(metadata, error))
3055
 
                {
3056
 
                        // parse failed
3057
 
                        return false;
3058
 
                }
3059
 
 
3060
 
                if (m_ses.m_alerts.should_post<metadata_received_alert>())
3061
 
                {
3062
 
                        m_ses.m_alerts.post_alert(metadata_received_alert(
3063
 
                                get_handle()));
3064
 
                }
3065
 
 
3066
 
                init();
3067
 
 
3068
 
                return true;
3069
 
        }
3070
 
 
3071
 
        bool torrent::attach_peer(peer_connection* p)
3072
 
        {
3073
 
//              INVARIANT_CHECK;
3074
 
 
3075
 
                TORRENT_ASSERT(p != 0);
3076
 
                TORRENT_ASSERT(!p->is_local());
3077
 
 
3078
 
                m_has_incoming = true;
3079
 
 
3080
 
                if ((m_state == torrent_status::queued_for_checking
3081
 
                        || m_state == torrent_status::checking_files
3082
 
                        || m_state == torrent_status::checking_resume_data)
3083
 
                        && valid_metadata())
3084
 
                {
3085
 
                        p->disconnect("torrent is not ready to accept peers");
3086
 
                        return false;
3087
 
                }
3088
 
                
3089
 
                if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
3090
 
                {
3091
 
                        p->disconnect("peer is not properly constructed");
3092
 
                        return false;
3093
 
                }
3094
 
 
3095
 
                if (m_ses.is_aborted())
3096
 
                {
3097
 
                        p->disconnect("session is closing");
3098
 
                        return false;
3099
 
                }
3100
 
 
3101
 
                if (int(m_connections.size()) >= m_max_connections)
3102
 
                {
3103
 
                        p->disconnect("reached connection limit");
3104
 
                        return false;
3105
 
                }
3106
 
 
3107
 
#ifndef BOOST_NO_EXCEPTIONS
3108
 
                try
3109
 
                {
3110
 
#endif
3111
 
#ifndef TORRENT_DISABLE_EXTENSIONS
3112
 
                        for (extension_list_t::iterator i = m_extensions.begin()
3113
 
                                , end(m_extensions.end()); i != end; ++i)
3114
 
                        {
3115
 
                                boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
3116
 
                                if (pp) p->add_extension(pp);
3117
 
                        }
3118
 
#endif
3119
 
                        if (!m_policy.new_connection(*p))
3120
 
                                return false;
3121
 
#ifndef BOOST_NO_EXCEPTIONS
3122
 
                }
3123
 
                catch (std::exception& e)
3124
 
                {
3125
 
#if defined TORRENT_LOGGING
3126
 
                        (*m_ses.m_logger) << time_now_string() << " CLOSING CONNECTION "
3127
 
                                << p->remote() << " policy::new_connection threw: " << e.what() << "\n";
3128
 
#endif
3129
 
                        p->disconnect(e.what());
3130
 
                        return false;
3131
 
                }
3132
 
#endif
3133
 
                TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
3134
 
                peer_iterator ci = m_connections.insert(p).first;
3135
 
#ifdef TORRENT_DEBUG
3136
 
                error_code ec;
3137
 
                TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
3138
 
#endif
3139
 
 
3140
 
#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
3141
 
                m_policy.check_invariant();
3142
 
#endif
3143
 
                return true;
3144
 
        }
3145
 
 
3146
 
        bool torrent::want_more_peers() const
3147
 
        {
3148
 
                return int(m_connections.size()) < m_max_connections
3149
 
                        && !is_paused()
3150
 
                        && m_state != torrent_status::checking_files
3151
 
                        && m_state != torrent_status::checking_resume_data
3152
 
                        && (m_state != torrent_status::queued_for_checking
3153
 
                                || !valid_metadata())
3154
 
                        && m_policy.num_connect_candidates() > 0
3155
 
                        && !m_abort;
3156
 
        }
3157
 
 
3158
 
        void torrent::disconnect_all()
3159
 
        {
3160
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3161
 
 
3162
 
// doesn't work with the m_paused -> m_num_peers == 0 condition
3163
 
//              INVARIANT_CHECK;
3164
 
 
3165
 
                while (!m_connections.empty())
3166
 
                {
3167
 
                        peer_connection* p = *m_connections.begin();
3168
 
                        TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
3169
 
 
3170
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3171
 
                        if (m_abort)
3172
 
                                (*p->m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
3173
 
                        else
3174
 
                                (*p->m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
3175
 
#endif
3176
 
#ifdef TORRENT_DEBUG
3177
 
                        std::size_t size = m_connections.size();
3178
 
#endif
3179
 
                        if (p->is_disconnecting())
3180
 
                                m_connections.erase(m_connections.begin());
3181
 
                        else
3182
 
                                p->disconnect(m_abort?"stopping torrent":"pausing torrent");
3183
 
                        TORRENT_ASSERT(m_connections.size() <= size);
3184
 
                }
3185
 
        }
3186
 
 
3187
 
        namespace
3188
 
        {
3189
 
                // this returns true if lhs is a better disconnect candidate than rhs
3190
 
                bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
3191
 
                {
3192
 
                        // prefer to disconnect peers we're not interested in
3193
 
                        if (lhs->is_interesting() != rhs->is_interesting())
3194
 
                                return rhs->is_interesting();
3195
 
 
3196
 
                        // prefer to disconnect peers that are not seeds
3197
 
                        if (lhs->is_seed() != rhs->is_seed())
3198
 
                                return rhs->is_seed();
3199
 
 
3200
 
                        // prefer to disconnect peers that are on parole
3201
 
                        if (lhs->on_parole() != rhs->on_parole())
3202
 
                                return lhs->on_parole();
3203
 
 
3204
 
                        // prefer to disconnect peers that send data at a lower rate
3205
 
                        size_type lhs_transferred = lhs->statistics().total_payload_download();
3206
 
                        size_type rhs_transferred = rhs->statistics().total_payload_download();
3207
 
 
3208
 
                        if (lhs_transferred != rhs_transferred
3209
 
                                && lhs_transferred > 0
3210
 
                                && rhs_transferred > 0)
3211
 
                        {
3212
 
                                ptime now = time_now();
3213
 
                                size_type lhs_time_connected = total_seconds(now - lhs->connected_time());
3214
 
                                size_type rhs_time_connected = total_seconds(now - rhs->connected_time());
3215
 
 
3216
 
                                double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1);
3217
 
                                double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1);
3218
 
                        
3219
 
                                return lhs_rate < rhs_rate;
3220
 
                        }
3221
 
 
3222
 
                        // prefer to disconnect peers that chokes us
3223
 
                        if (lhs->is_choked() != rhs->is_choked())
3224
 
                                return lhs->is_choked();
3225
 
 
3226
 
                        return lhs->last_received() < rhs->last_received();
3227
 
                }
3228
 
        }
3229
 
 
3230
 
        int torrent::disconnect_peers(int num)
3231
 
        {
3232
 
                INVARIANT_CHECK;
3233
 
 
3234
 
                int ret = 0;
3235
 
                // buils a list of all connected peers and sort it by 'disconnectability'.
3236
 
                std::vector<peer_connection*> peers(m_connections.size());
3237
 
                std::copy(m_connections.begin(), m_connections.end(), peers.begin());
3238
 
                std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2));
3239
 
 
3240
 
                // never disconnect peers that connected less than 90 seconds ago
3241
 
                ptime cut_off = time_now() - seconds(90);
3242
 
 
3243
 
                for (std::vector<peer_connection*>::iterator i = peers.begin()
3244
 
                        , end(peers.end()); i != end && ret < num; ++i)
3245
 
                {
3246
 
                        peer_connection* p = *i;
3247
 
                        if (p->connected_time() > cut_off) continue;
3248
 
                        ++ret;
3249
 
                        p->disconnect("optimistic disconnect");
3250
 
                }
3251
 
                return ret;
3252
 
        }
3253
 
 
3254
 
        int torrent::bandwidth_throttle(int channel) const
3255
 
        {
3256
 
                return m_bandwidth_limit[channel].throttle();
3257
 
        }
3258
 
 
3259
 
        int torrent::bandwidth_queue_size(int channel) const
3260
 
        {
3261
 
                return (int)m_bandwidth_queue[channel].size();
3262
 
        }
3263
 
 
3264
 
        void torrent::request_bandwidth(int channel
3265
 
                , boost::intrusive_ptr<peer_connection> const& p
3266
 
                , int max_block_size, int priority)
3267
 
        {
3268
 
                TORRENT_ASSERT(max_block_size > 0);
3269
 
                TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
3270
 
                TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
3271
 
                TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3272
 
                int block_size = (std::min)(m_bandwidth_limit[channel].throttle() / 10
3273
 
                        , max_block_size);
3274
 
                if (block_size <= 0) block_size = 1;
3275
 
 
3276
 
                if (m_bandwidth_limit[channel].max_assignable() > 0)
3277
 
                {
3278
 
                        perform_bandwidth_request(channel, p, block_size, priority);
3279
 
                }
3280
 
                else
3281
 
                {
3282
 
                        // skip forward in the queue until we find a prioritized peer
3283
 
                        // or hit the front of it.
3284
 
                        queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin();
3285
 
                        while (i != m_bandwidth_queue[channel].rend() && priority > i->priority)
3286
 
                        {
3287
 
                                ++i->priority;
3288
 
                                ++i;
3289
 
                        }
3290
 
                        m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry<peer_connection, torrent>(
3291
 
                                p, block_size, priority));
3292
 
                }
3293
 
        }
3294
 
 
3295
 
        void torrent::expire_bandwidth(int channel, int amount)
3296
 
        {
3297
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3298
 
 
3299
 
                INVARIANT_CHECK;
3300
 
                
3301
 
                TORRENT_ASSERT(amount > 0);
3302
 
                m_bandwidth_limit[channel].expire(amount);
3303
 
                queue_t tmp;
3304
 
                while (!m_bandwidth_queue[channel].empty())
3305
 
                {
3306
 
                        bw_queue_entry<peer_connection, torrent> qe = m_bandwidth_queue[channel].front();
3307
 
                        if (m_bandwidth_limit[channel].max_assignable() == 0)
3308
 
                                break;
3309
 
                        m_bandwidth_queue[channel].pop_front();
3310
 
                        if (qe.peer->max_assignable_bandwidth(channel) <= 0)
3311
 
                        {
3312
 
                                TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
3313
 
                                if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
3314
 
                                continue;
3315
 
                        }
3316
 
                        perform_bandwidth_request(channel, qe.peer
3317
 
                                , qe.max_block_size, qe.priority);
3318
 
                }
3319
 
                m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
3320
 
        }
3321
 
 
3322
 
        void torrent::perform_bandwidth_request(int channel
3323
 
                , boost::intrusive_ptr<peer_connection> const& p
3324
 
                , int block_size
3325
 
                , int priority)
3326
 
        {
3327
 
                TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3328
 
                p->m_channel_state[channel] = peer_info::bw_global;
3329
 
                m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
3330
 
                        , block_size, priority);
3331
 
                m_bandwidth_limit[channel].assign(block_size);
3332
 
        }
3333
 
 
3334
 
        void torrent::assign_bandwidth(int channel, int amount, int blk)
3335
 
        {
3336
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3337
 
 
3338
 
                TORRENT_ASSERT(amount > 0);
3339
 
                TORRENT_ASSERT(amount <= blk);
3340
 
                if (amount < blk)
3341
 
                        expire_bandwidth(channel, blk - amount);
3342
 
        }
3343
 
 
3344
 
        // called when torrent is finished (all interesting
3345
 
        // pieces have been downloaded)
3346
 
        void torrent::finished()
3347
 
        {
3348
 
                INVARIANT_CHECK;
3349
 
 
3350
 
                TORRENT_ASSERT(is_finished());
3351
 
                TORRENT_ASSERT(m_state != torrent_status::finished && m_state != torrent_status::seeding);
3352
 
 
3353
 
                if (alerts().should_post<torrent_finished_alert>())
3354
 
                {
3355
 
                        alerts().post_alert(torrent_finished_alert(
3356
 
                                get_handle()));
3357
 
                }
3358
 
 
3359
 
                set_state(torrent_status::finished);
3360
 
                set_queue_position(-1);
3361
 
 
3362
 
                // we have to call completed() before we start
3363
 
                // disconnecting peers, since there's an assert
3364
 
                // to make sure we're cleared the piece picker
3365
 
                if (is_seed()) completed();
3366
 
 
3367
 
                // disconnect all seeds
3368
 
                // TODO: should disconnect all peers that have the pieces we have
3369
 
                // not just seeds
3370
 
                std::vector<peer_connection*> seeds;
3371
 
                for (peer_iterator i = m_connections.begin();
3372
 
                        i != m_connections.end(); ++i)
3373
 
                {
3374
 
                        peer_connection* p = *i;
3375
 
                        TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
3376
 
                        if (p->upload_only())
3377
 
                        {
3378
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3379
 
                                (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
3380
 
#endif
3381
 
                                seeds.push_back(p);
3382
 
                        }
3383
 
                }
3384
 
                std::for_each(seeds.begin(), seeds.end()
3385
 
                        , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed", 0));
3386
 
 
3387
 
                m_policy.recalculate_connect_candidates();
3388
 
 
3389
 
                TORRENT_ASSERT(m_storage);
3390
 
                // we need to keep the object alive during this operation
3391
 
                m_storage->async_release_files(
3392
 
                        bind(&torrent::on_files_released, shared_from_this(), _1, _2));
3393
 
        }
3394
 
 
3395
 
        // this is called when we were finished, but some files were
3396
 
        // marked for downloading, and we are no longer finished        
3397
 
        void torrent::resume_download()
3398
 
        {
3399
 
                INVARIANT_CHECK;
3400
 
        
3401
 
                TORRENT_ASSERT(!is_finished());
3402
 
                set_state(torrent_status::downloading);
3403
 
                set_queue_position((std::numeric_limits<int>::max)());
3404
 
                m_policy.recalculate_connect_candidates();
3405
 
        }
3406
 
 
3407
 
        // called when torrent is complete (all pieces downloaded)
3408
 
        void torrent::completed()
3409
 
        {
3410
 
                m_picker.reset();
3411
 
 
3412
 
                set_state(torrent_status::seeding);
3413
 
                if (!m_complete_sent && m_announcing) announce_with_tracker();
3414
 
        }
3415
 
 
3416
 
        // this will move the tracker with the given index
3417
 
        // to a prioritized position in the list (move it towards
3418
 
        // the begining) and return the new index to the tracker.
3419
 
        int torrent::prioritize_tracker(int index)
3420
 
        {
3421
 
                INVARIANT_CHECK;
3422
 
 
3423
 
                TORRENT_ASSERT(index >= 0);
3424
 
                if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
3425
 
 
3426
 
                while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
3427
 
                {
3428
 
                        std::swap(m_trackers[index].url, m_trackers[index-1].url);
3429
 
                        --index;
3430
 
                }
3431
 
                return index;
3432
 
        }
3433
 
 
3434
 
        void torrent::try_next_tracker(tracker_request const& req)
3435
 
        {
3436
 
                INVARIANT_CHECK;
3437
 
 
3438
 
                ++m_currently_trying_tracker;
3439
 
 
3440
 
                if ((unsigned)m_currently_trying_tracker < m_trackers.size())
3441
 
                {
3442
 
                        announce_with_tracker(req.event);
3443
 
                        return;
3444
 
                }
3445
 
 
3446
 
                int delay = tracker_retry_delay_min
3447
 
                        + (std::min)(int(m_failed_trackers), int(tracker_failed_max))
3448
 
                        * (tracker_retry_delay_max - tracker_retry_delay_min)
3449
 
                        / tracker_failed_max;
3450
 
 
3451
 
                ++m_failed_trackers;
3452
 
                // if we've looped the tracker list, wait a bit before retrying
3453
 
                m_currently_trying_tracker = 0;
3454
 
 
3455
 
                // if we're stopping, just give up. Don't bother retrying
3456
 
                if (req.event == tracker_request::stopped)
3457
 
                        return;
3458
 
 
3459
 
                restart_tracker_timer(time_now() + seconds(delay));
3460
 
 
3461
 
#ifndef TORRENT_DISABLE_DHT
3462
 
                if (m_abort) return;
3463
 
 
3464
 
                // only start the announce if we want to announce with the dht
3465
 
                ptime now = time_now();
3466
 
                if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
3467
 
                {
3468
 
                        // force the DHT to reannounce
3469
 
                        m_last_dht_announce = now;
3470
 
                        boost::weak_ptr<torrent> self(shared_from_this());
3471
 
                        m_ses.m_dht->announce(m_torrent_file->info_hash()
3472
 
                                , m_ses.m_listen_sockets.front().external_port
3473
 
                                , bind(&torrent::on_dht_announce_response_disp, self, _1));
3474
 
                }
3475
 
#endif
3476
 
 
3477
 
        }
3478
 
 
3479
 
        void torrent::files_checked()
3480
 
        {
3481
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3482
 
                
3483
 
                TORRENT_ASSERT(m_torrent_file->is_valid());
3484
 
 
3485
 
                if (m_abort) return;
3486
 
 
3487
 
                // we might be finished already, in which case we should
3488
 
                // not switch to downloading mode.
3489
 
                if (m_state != torrent_status::finished)
3490
 
                        set_state(torrent_status::downloading);
3491
 
 
3492
 
                INVARIANT_CHECK;
3493
 
 
3494
 
                if (m_ses.m_alerts.should_post<torrent_checked_alert>())
3495
 
                {
3496
 
                        m_ses.m_alerts.post_alert(torrent_checked_alert(
3497
 
                                get_handle()));
3498
 
                }
3499
 
                
3500
 
                if (!is_seed())
3501
 
                {
3502
 
                        // if we just finished checking and we're not a seed, we are
3503
 
                        // likely to be unpaused
3504
 
                        if (m_ses.m_auto_manage_time_scaler > 1)
3505
 
                                m_ses.m_auto_manage_time_scaler = 1;
3506
 
 
3507
 
                        if (is_finished() && m_state != torrent_status::finished) finished();
3508
 
                }
3509
 
                else
3510
 
                {
3511
 
                        m_complete_sent = true;
3512
 
                        if (m_state != torrent_status::finished) finished();
3513
 
                }
3514
 
 
3515
 
#ifndef TORRENT_DISABLE_EXTENSIONS
3516
 
                for (extension_list_t::iterator i = m_extensions.begin()
3517
 
                        , end(m_extensions.end()); i != end; ++i)
3518
 
                {
3519
 
#ifndef BOOST_NO_EXCEPTIONS
3520
 
                        try {
3521
 
#endif
3522
 
                                (*i)->on_files_checked();
3523
 
#ifndef BOOST_NO_EXCEPTIONS
3524
 
                        } catch (std::exception&) {}
3525
 
#endif
3526
 
                }
3527
 
#endif
3528
 
 
3529
 
                if (!m_connections_initialized)
3530
 
                {
3531
 
                        m_connections_initialized = true;
3532
 
                        // all peer connections have to initialize themselves now that the metadata
3533
 
                        // is available
3534
 
                        for (torrent::peer_iterator i = m_connections.begin();
3535
 
                                i != m_connections.end();)
3536
 
                        {
3537
 
                                peer_connection* pc = *i;
3538
 
                                ++i;
3539
 
                                if (pc->is_disconnecting()) continue;
3540
 
                                pc->on_metadata_impl();
3541
 
                                if (pc->is_disconnecting()) continue;
3542
 
                                pc->init();
3543
 
                        }
3544
 
                }
3545
 
 
3546
 
                m_files_checked = true;
3547
 
 
3548
 
                start_announcing();
3549
 
        }
3550
 
 
3551
 
        alert_manager& torrent::alerts() const
3552
 
        {
3553
 
                return m_ses.m_alerts;
3554
 
        }
3555
 
 
3556
 
        fs::path torrent::save_path() const
3557
 
        {
3558
 
                return m_save_path;
3559
 
        }
3560
 
 
3561
 
        bool torrent::rename_file(int index, std::string const& name)
3562
 
        {
3563
 
                INVARIANT_CHECK;
3564
 
 
3565
 
                TORRENT_ASSERT(index >= 0);
3566
 
                TORRENT_ASSERT(index < m_torrent_file->num_files());
3567
 
 
3568
 
                if (!m_owning_storage.get()) return false;
3569
 
 
3570
 
                m_owning_storage->async_rename_file(index, name
3571
 
                        , bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
3572
 
                return true;
3573
 
        }
3574
 
 
3575
 
        void torrent::move_storage(fs::path const& save_path)
3576
 
        {
3577
 
                INVARIANT_CHECK;
3578
 
 
3579
 
                if (m_owning_storage.get())
3580
 
                {
3581
 
                        m_owning_storage->async_move_storage(save_path
3582
 
                                , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
3583
 
                }
3584
 
                else
3585
 
                {
3586
 
                        m_save_path = save_path;
3587
 
                        if (alerts().should_post<storage_moved_alert>())
3588
 
                        {
3589
 
                                alerts().post_alert(storage_moved_alert(get_handle(), m_save_path.string()));
3590
 
                        }
3591
 
                }
3592
 
        }
3593
 
 
3594
 
        void torrent::on_storage_moved(int ret, disk_io_job const& j)
3595
 
        {
3596
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3597
 
 
3598
 
                if (ret == 0)
3599
 
                {
3600
 
                        if (alerts().should_post<storage_moved_alert>())
3601
 
                        {
3602
 
                                alerts().post_alert(storage_moved_alert(get_handle(), j.str));
3603
 
                        }
3604
 
                        m_save_path = j.str;
3605
 
                }
3606
 
                else
3607
 
                {
3608
 
                        if (alerts().should_post<storage_moved_failed_alert>())
3609
 
                        {
3610
 
                                alerts().post_alert(storage_moved_failed_alert(get_handle(), j.error));
3611
 
                        }
3612
 
                }
3613
 
        }
3614
 
 
3615
 
        piece_manager& torrent::filesystem()
3616
 
        {
3617
 
                TORRENT_ASSERT(m_owning_storage.get());
3618
 
                TORRENT_ASSERT(m_storage);
3619
 
                return *m_storage;
3620
 
        }
3621
 
 
3622
 
 
3623
 
        torrent_handle torrent::get_handle()
3624
 
        {
3625
 
                return torrent_handle(shared_from_this());
3626
 
        }
3627
 
 
3628
 
        session_settings const& torrent::settings() const
3629
 
        {
3630
 
                return m_ses.settings();
3631
 
        }
3632
 
 
3633
 
#ifdef TORRENT_DEBUG
3634
 
        void torrent::check_invariant() const
3635
 
        {
3636
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3637
 
 
3638
 
                if (is_paused()) TORRENT_ASSERT(num_peers() == 0);
3639
 
 
3640
 
                if (!should_check_files())
3641
 
                        TORRENT_ASSERT(m_state != torrent_status::checking_files);
3642
 
                else
3643
 
                        TORRENT_ASSERT(m_queued_for_checking);
3644
 
  
3645
 
                if (!m_ses.m_queued_for_checking.empty())
3646
 
                {
3647
 
                        // if there are torrents waiting to be checked
3648
 
                        // assert that there's a torrent that is being
3649
 
                        // processed right now
3650
 
                        int found = 0;
3651
 
                        int found_active = 0;
3652
 
                        for (aux::session_impl::torrent_map::iterator i = m_ses.m_torrents.begin()
3653
 
                                , end(m_ses.m_torrents.end()); i != end; ++i)
3654
 
                                if (i->second->m_state == torrent_status::checking_files)
3655
 
                                {
3656
 
                                        ++found;
3657
 
                                        if (i->second->should_check_files()) ++found_active;
3658
 
                                }
3659
 
                        // the case of 2 is in the special case where one switches over from
3660
 
                        // checking to complete
3661
 
                        TORRENT_ASSERT(found_active >= 1);
3662
 
                        TORRENT_ASSERT(found_active <= 2);
3663
 
                        TORRENT_ASSERT(found >= 1);
3664
 
                }
3665
 
 
3666
 
                TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
3667
 
                        || m_resume_entry.type() == lazy_entry::none_t);
3668
 
 
3669
 
                TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
3670
 
                TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
3671
 
 
3672
 
                for (int c = 0; c < 2; ++c)
3673
 
                {
3674
 
                        queue_t::const_iterator j = m_bandwidth_queue[c].begin();
3675
 
                        if (j == m_bandwidth_queue[c].end()) continue;
3676
 
                        ++j;
3677
 
                        for (queue_t::const_iterator i = m_bandwidth_queue[c].begin()
3678
 
                                , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j)
3679
 
                                TORRENT_ASSERT(i->priority >= j->priority);
3680
 
                }
3681
 
 
3682
 
                int num_uploads = 0;
3683
 
                std::map<piece_block, int> num_requests;
3684
 
                for (const_peer_iterator i = begin(); i != end(); ++i)
3685
 
                {
3686
 
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3687
 
                        // make sure this peer is not a dangling pointer
3688
 
                        TORRENT_ASSERT(m_ses.has_peer(*i));
3689
 
#endif
3690
 
                        peer_connection const& p = *(*i);
3691
 
                        for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
3692
 
                                , end(p.request_queue().end()); i != end; ++i)
3693
 
                                ++num_requests[*i];
3694
 
                        for (std::deque<pending_block>::const_iterator i = p.download_queue().begin()
3695
 
                                , end(p.download_queue().end()); i != end; ++i)
3696
 
                                ++num_requests[i->block];
3697
 
                        if (!p.is_choked()) ++num_uploads;
3698
 
                        torrent* associated_torrent = p.associated_torrent().lock().get();
3699
 
                        if (associated_torrent != this)
3700
 
                                TORRENT_ASSERT(false);
3701
 
                }
3702
 
                TORRENT_ASSERT(num_uploads == m_num_uploads);
3703
 
 
3704
 
                if (has_picker())
3705
 
                {
3706
 
                        for (std::map<piece_block, int>::iterator i = num_requests.begin()
3707
 
                                , end(num_requests.end()); i != end; ++i)
3708
 
                        {
3709
 
                                if (!m_picker->is_downloaded(i->first))
3710
 
                                        TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
3711
 
                        }
3712
 
                        TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
3713
 
                }
3714
 
 
3715
 
                if (valid_metadata())
3716
 
                {
3717
 
                        TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
3718
 
                }
3719
 
                else
3720
 
                {
3721
 
                        TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == 0);
3722
 
                }
3723
 
 
3724
 
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3725
 
                for (policy::const_iterator i = m_policy.begin_peer()
3726
 
                        , end(m_policy.end_peer()); i != end; ++i)
3727
 
                {
3728
 
                        TORRENT_ASSERT(i->second.addr == i->first);
3729
 
                }
3730
 
#endif
3731
 
 
3732
 
                size_type total_done = quantized_bytes_done();
3733
 
                if (m_torrent_file->is_valid())
3734
 
                {
3735
 
                        if (is_seed())
3736
 
                                TORRENT_ASSERT(total_done == m_torrent_file->total_size());
3737
 
                        else
3738
 
                                TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked);
3739
 
 
3740
 
                        TORRENT_ASSERT(m_block_size <= m_torrent_file->piece_length());
3741
 
                }
3742
 
                else
3743
 
                {
3744
 
                        TORRENT_ASSERT(total_done == 0);
3745
 
                }
3746
 
 
3747
 
                if (m_picker && !m_abort)
3748
 
                {
3749
 
                        // make sure that pieces that have completed the download
3750
 
                        // of all their blocks are in the disk io thread's queue
3751
 
                        // to be checked.
3752
 
                        const std::vector<piece_picker::downloading_piece>& dl_queue
3753
 
                                = m_picker->get_download_queue();
3754
 
                        for (std::vector<piece_picker::downloading_piece>::const_iterator i =
3755
 
                                dl_queue.begin(); i != dl_queue.end(); ++i)
3756
 
                        {
3757
 
                                const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
3758
 
 
3759
 
                                bool complete = true;
3760
 
                                for (int j = 0; j < blocks_per_piece; ++j)
3761
 
                                {
3762
 
                                        if (i->info[j].state == piece_picker::block_info::state_finished)
3763
 
                                                continue;
3764
 
                                        complete = false;
3765
 
                                        break;
3766
 
                                }
3767
 
                        }
3768
 
                }
3769
 
                        
3770
 
// This check is very expensive.
3771
 
                TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
3772
 
                TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
3773
 
//              if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
3774
 
        }
3775
 
#endif
3776
 
 
3777
 
        void torrent::set_sequential_download(bool sd)
3778
 
        { m_sequential_download = sd; }
3779
 
 
3780
 
        void torrent::set_queue_position(int p)
3781
 
        {
3782
 
                TORRENT_ASSERT((p == -1) == is_finished()
3783
 
                        || (!m_auto_managed && p == -1)
3784
 
                        || (m_abort && p == -1));
3785
 
                if (is_finished() && p != -1) return;
3786
 
                if (p == m_sequence_number) return;
3787
 
 
3788
 
                session_impl::torrent_map& torrents = m_ses.m_torrents;
3789
 
                if (p >= 0 && m_sequence_number == -1)
3790
 
                {
3791
 
                        int max_seq = -1;
3792
 
                        for (session_impl::torrent_map::iterator i = torrents.begin()
3793
 
                                , end(torrents.end()); i != end; ++i)
3794
 
                        {
3795
 
                                torrent* t = i->second.get();
3796
 
                                if (t->m_sequence_number > max_seq) max_seq = t->m_sequence_number;
3797
 
                        }
3798
 
                        m_sequence_number = (std::min)(max_seq + 1, p);
3799
 
                }
3800
 
                else if (p < 0)
3801
 
                {
3802
 
                        for (session_impl::torrent_map::iterator i = torrents.begin()
3803
 
                                , end(torrents.end()); i != end; ++i)
3804
 
                        {
3805
 
                                torrent* t = i->second.get();
3806
 
                                if (t == this) continue;
3807
 
                                if (t->m_sequence_number >= m_sequence_number
3808
 
                                        && t->m_sequence_number != -1)
3809
 
                                        --t->m_sequence_number;
3810
 
                        }
3811
 
                        m_sequence_number = p;
3812
 
                }
3813
 
                else if (p < m_sequence_number)
3814
 
                {
3815
 
                        for (session_impl::torrent_map::iterator i = torrents.begin()
3816
 
                                , end(torrents.end()); i != end; ++i)
3817
 
                        {
3818
 
                                torrent* t = i->second.get();
3819
 
                                if (t == this) continue;
3820
 
                                if (t->m_sequence_number >= p 
3821
 
                                        && t->m_sequence_number < m_sequence_number
3822
 
                                        && t->m_sequence_number != -1)
3823
 
                                        ++t->m_sequence_number;
3824
 
                        }
3825
 
                        m_sequence_number = p;
3826
 
                }
3827
 
                else if (p > m_sequence_number)
3828
 
                {
3829
 
                        int max_seq = 0;
3830
 
                        for (session_impl::torrent_map::iterator i = torrents.begin()
3831
 
                                , end(torrents.end()); i != end; ++i)
3832
 
                        {
3833
 
                                torrent* t = i->second.get();
3834
 
                                int pos = t->m_sequence_number;
3835
 
                                if (pos > max_seq) max_seq = pos;
3836
 
                                if (t == this) continue;
3837
 
 
3838
 
                                if (pos <= p
3839
 
                                                && pos > m_sequence_number
3840
 
                                                && pos != -1)
3841
 
                                        --t->m_sequence_number;
3842
 
 
3843
 
                        }
3844
 
                        m_sequence_number = (std::min)(max_seq, p);
3845
 
                }
3846
 
 
3847
 
                if (m_ses.m_auto_manage_time_scaler > 2)
3848
 
                        m_ses.m_auto_manage_time_scaler = 2;
3849
 
        }
3850
 
 
3851
 
        void torrent::set_max_uploads(int limit)
3852
 
        {
3853
 
                TORRENT_ASSERT(limit >= -1);
3854
 
                if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3855
 
                m_max_uploads = limit;
3856
 
        }
3857
 
 
3858
 
        void torrent::set_max_connections(int limit)
3859
 
        {
3860
 
                TORRENT_ASSERT(limit >= -1);
3861
 
                if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3862
 
                m_max_connections = limit;
3863
 
        }
3864
 
 
3865
 
        void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
3866
 
        {
3867
 
                TORRENT_ASSERT(limit >= -1);
3868
 
                peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3869
 
                        , bind(&peer_connection::remote, _1) == ip);
3870
 
                if (i == m_connections.end()) return;
3871
 
                (*i)->set_upload_limit(limit);
3872
 
        }
3873
 
 
3874
 
        void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
3875
 
        {
3876
 
                TORRENT_ASSERT(limit >= -1);
3877
 
                peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3878
 
                        , bind(&peer_connection::remote, _1) == ip);
3879
 
                if (i == m_connections.end()) return;
3880
 
                (*i)->set_download_limit(limit);
3881
 
        }
3882
 
 
3883
 
        void torrent::set_upload_limit(int limit)
3884
 
        {
3885
 
                TORRENT_ASSERT(limit >= -1);
3886
 
                if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3887
 
                m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
3888
 
        }
3889
 
 
3890
 
        int torrent::upload_limit() const
3891
 
        {
3892
 
                int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
3893
 
                if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3894
 
                return limit;
3895
 
        }
3896
 
 
3897
 
        void torrent::set_download_limit(int limit)
3898
 
        {
3899
 
                TORRENT_ASSERT(limit >= -1);
3900
 
                if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3901
 
                m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
3902
 
        }
3903
 
 
3904
 
        int torrent::download_limit() const
3905
 
        {
3906
 
                int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
3907
 
                if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3908
 
                return limit;
3909
 
        }
3910
 
 
3911
 
        void torrent::delete_files()
3912
 
        {
3913
 
#if defined TORRENT_VERBOSE_LOGGING
3914
 
                for (peer_iterator i = m_connections.begin();
3915
 
                        i != m_connections.end(); ++i)
3916
 
                {
3917
 
                        (*(*i)->m_logger) << "*** DELETING FILES IN TORRENT\n";
3918
 
                }
3919
 
#endif
3920
 
 
3921
 
                disconnect_all();
3922
 
                stop_announcing();
3923
 
 
3924
 
                if (m_owning_storage.get())
3925
 
                {
3926
 
                        TORRENT_ASSERT(m_storage);
3927
 
                        m_storage->async_delete_files(
3928
 
                                bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
3929
 
                }
3930
 
        }
3931
 
 
3932
 
        void torrent::clear_error()
3933
 
        {
3934
 
                if (m_error.empty()) return;
3935
 
                bool checking_files = should_check_files();
3936
 
                if (m_ses.m_auto_manage_time_scaler > 2)
3937
 
                        m_ses.m_auto_manage_time_scaler = 2;
3938
 
                m_error.clear();
3939
 
                if (!checking_files && should_check_files())
3940
 
                        queue_torrent_check();
3941
 
        }
3942
 
 
3943
 
        void torrent::set_error(std::string const& msg)
3944
 
        {
3945
 
                bool checking_files = should_check_files();
3946
 
                m_error = msg;
3947
 
                if (checking_files && !should_check_files())
3948
 
                {
3949
 
                        // stop checking
3950
 
                        m_storage->abort_disk_io();
3951
 
                        dequeue_torrent_check();
3952
 
                        set_state(torrent_status::queued_for_checking);
3953
 
                }
3954
 
        }
3955
 
 
3956
 
        void torrent::auto_managed(bool a)
3957
 
        {
3958
 
                INVARIANT_CHECK;
3959
 
 
3960
 
                if (m_auto_managed == a) return;
3961
 
                bool checking_files = should_check_files();
3962
 
                m_auto_managed = a;
3963
 
                // recalculate which torrents should be
3964
 
                // paused
3965
 
                m_ses.m_auto_manage_time_scaler = 0;
3966
 
 
3967
 
                if (!checking_files && should_check_files())
3968
 
                {
3969
 
                        queue_torrent_check();
3970
 
                }
3971
 
                else if (checking_files && !should_check_files())
3972
 
                {
3973
 
                        // stop checking
3974
 
                        m_storage->abort_disk_io();
3975
 
                        dequeue_torrent_check();
3976
 
                        set_state(torrent_status::queued_for_checking);
3977
 
                }
3978
 
        }
3979
 
 
3980
 
        // the higher seed rank, the more important to seed
3981
 
        int torrent::seed_rank(session_settings const& s) const
3982
 
        {
3983
 
                enum flags
3984
 
                {
3985
 
                        seed_ratio_not_met = 0x400000,
3986
 
                        recently_started = 0x200000,
3987
 
                        no_seeds = 0x100000,
3988
 
                        prio_mask = 0xfffff
3989
 
                };
3990
 
 
3991
 
                if (!is_seed()) return 0;
3992
 
 
3993
 
                int ret = 0;
3994
 
 
3995
 
                ptime now(time_now());
3996
 
 
3997
 
                int seed_time = total_seconds(m_seeding_time);
3998
 
                int download_time = total_seconds(m_active_time) - seed_time;
3999
 
 
4000
 
                // if we haven't yet met the seed limits, set the seed_ratio_not_met
4001
 
                // flag. That will make this seed prioritized
4002
 
                // downloaded may be 0 if the torrent is 0-sized
4003
 
                size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
4004
 
                if (seed_time < s.seed_time_limit
4005
 
                        && (download_time > 1 && seed_time / download_time < s.seed_time_ratio_limit)
4006
 
                        && downloaded > 0
4007
 
                        && m_total_uploaded / downloaded < s.share_ratio_limit)
4008
 
                        ret |= seed_ratio_not_met;
4009
 
 
4010
 
                // if this torrent is running, and it was started less
4011
 
                // than 30 minutes ago, give it priority, to avoid oscillation
4012
 
                if (!is_paused() && now - m_started < minutes(30))
4013
 
                        ret |= recently_started;
4014
 
 
4015
 
                // if we have any scrape data, use it to calculate
4016
 
                // seed rank
4017
 
                int seeds = 0;
4018
 
                int downloaders = 0;
4019
 
 
4020
 
                if (m_complete >= 0) seeds = m_complete;
4021
 
                else seeds = m_policy.num_seeds();
4022
 
 
4023
 
                if (m_incomplete >= 0) downloaders = m_incomplete;
4024
 
                else downloaders = m_policy.num_peers() - m_policy.num_seeds();
4025
 
 
4026
 
                if (seeds == 0)
4027
 
                {
4028
 
                        ret |= no_seeds;
4029
 
                        ret |= downloaders & prio_mask;
4030
 
                }
4031
 
                else
4032
 
                {
4033
 
                        ret |= (downloaders  * 100 / seeds) & prio_mask;
4034
 
                }
4035
 
 
4036
 
                return ret;
4037
 
        }
4038
 
 
4039
 
        // this is an async operation triggered by the client   
4040
 
        void torrent::save_resume_data()
4041
 
        {
4042
 
                INVARIANT_CHECK;
4043
 
        
4044
 
                if (m_owning_storage.get())
4045
 
                {
4046
 
                        TORRENT_ASSERT(m_storage);
4047
 
                        if (m_state == torrent_status::queued_for_checking
4048
 
                                || m_state == torrent_status::checking_files
4049
 
                                || m_state == torrent_status::checking_resume_data)
4050
 
                        {
4051
 
                                if (alerts().should_post<save_resume_data_alert>())
4052
 
                                {
4053
 
                                        boost::shared_ptr<entry> rd(new entry);
4054
 
                                        write_resume_data(*rd);
4055
 
                                        alerts().post_alert(save_resume_data_alert(rd
4056
 
                                                , get_handle()));
4057
 
                                }
4058
 
                        }
4059
 
                        else
4060
 
                        {
4061
 
                                m_storage->async_save_resume_data(
4062
 
                                        bind(&torrent::on_save_resume_data, shared_from_this(), _1, _2));
4063
 
                        }
4064
 
                }
4065
 
                else
4066
 
                {
4067
 
                        if (alerts().should_post<save_resume_data_failed_alert>())
4068
 
                        {
4069
 
                                alerts().post_alert(save_resume_data_failed_alert(get_handle()
4070
 
                                        , "save resume data failed, torrent is being destructed"));
4071
 
                        }
4072
 
                }
4073
 
        }
4074
 
 
4075
 
        bool torrent::should_check_files() const
4076
 
        {
4077
 
                return (m_state == torrent_status::checking_files
4078
 
                        || m_state == torrent_status::queued_for_checking)
4079
 
                        && (!m_paused || m_auto_managed)
4080
 
                        && m_error.empty()
4081
 
                        && !m_abort;
4082
 
        }
4083
 
 
4084
 
        bool torrent::is_paused() const
4085
 
        {
4086
 
                return m_paused || m_ses.is_paused();
4087
 
        }
4088
 
 
4089
 
        void torrent::pause()
4090
 
        {
4091
 
                INVARIANT_CHECK;
4092
 
 
4093
 
                if (m_paused) return;
4094
 
                bool checking_files = should_check_files();
4095
 
                m_paused = true;
4096
 
                if (!m_ses.is_paused())
4097
 
                        do_pause();
4098
 
                if (checking_files && !should_check_files())
4099
 
                {
4100
 
                        // stop checking
4101
 
                        m_storage->abort_disk_io();
4102
 
                        dequeue_torrent_check();
4103
 
                        set_state(torrent_status::queued_for_checking);
4104
 
                }
4105
 
        }
4106
 
 
4107
 
        void torrent::do_pause()
4108
 
        {
4109
 
                if (!is_paused()) return;
4110
 
 
4111
 
#ifndef TORRENT_DISABLE_EXTENSIONS
4112
 
                for (extension_list_t::iterator i = m_extensions.begin()
4113
 
                        , end(m_extensions.end()); i != end; ++i)
4114
 
                {
4115
 
#ifndef BOOST_NO_EXCEPTIONS
4116
 
                        try {
4117
 
#endif
4118
 
                                if ((*i)->on_pause()) return;
4119
 
#ifndef BOOST_NO_EXCEPTIONS
4120
 
                        } catch (std::exception&) {}
4121
 
#endif
4122
 
                }
4123
 
#endif
4124
 
 
4125
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
4126
 
                for (peer_iterator i = m_connections.begin();
4127
 
                        i != m_connections.end(); ++i)
4128
 
                {
4129
 
                        (*(*i)->m_logger) << "*** PAUSING TORRENT\n";
4130
 
                }
4131
 
#endif
4132
 
 
4133
 
                // this will make the storage close all
4134
 
                // files and flush all cached data
4135
 
                if (m_owning_storage.get())
4136
 
                {
4137
 
                        TORRENT_ASSERT(m_storage);
4138
 
                        m_storage->async_release_files(
4139
 
                                bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
4140
 
                        m_storage->async_clear_read_cache();
4141
 
                }
4142
 
                else
4143
 
                {
4144
 
                        if (alerts().should_post<torrent_paused_alert>())
4145
 
                                alerts().post_alert(torrent_paused_alert(get_handle()));
4146
 
                }
4147
 
 
4148
 
                disconnect_all();
4149
 
                stop_announcing();
4150
 
        }
4151
 
 
4152
 
        void torrent::resume()
4153
 
        {
4154
 
                INVARIANT_CHECK;
4155
 
 
4156
 
                if (!m_paused) return;
4157
 
                bool checking_files = should_check_files();
4158
 
                m_paused = false;
4159
 
                do_resume();
4160
 
                if (!checking_files && should_check_files())
4161
 
                        queue_torrent_check();
4162
 
        }
4163
 
 
4164
 
        void torrent::do_resume()
4165
 
        {
4166
 
                if (is_paused()) return;
4167
 
 
4168
 
#ifndef TORRENT_DISABLE_EXTENSIONS
4169
 
                for (extension_list_t::iterator i = m_extensions.begin()
4170
 
                        , end(m_extensions.end()); i != end; ++i)
4171
 
                {
4172
 
#ifndef BOOST_NO_EXCEPTIONS
4173
 
                        try {
4174
 
#endif
4175
 
                                if ((*i)->on_resume()) return;
4176
 
#ifndef BOOST_NO_EXCEPTIONS
4177
 
                        } catch (std::exception&) {}
4178
 
#endif
4179
 
                }
4180
 
#endif
4181
 
 
4182
 
                if (alerts().should_post<torrent_resumed_alert>())
4183
 
                        alerts().post_alert(torrent_resumed_alert(get_handle()));
4184
 
 
4185
 
                m_started = time_now();
4186
 
                m_error.clear();
4187
 
                start_announcing();
4188
 
        }
4189
 
 
4190
 
        void torrent::restart_tracker_timer(ptime announce_at)
4191
 
        {
4192
 
                if (!m_announcing) return;
4193
 
 
4194
 
                m_next_tracker_announce = announce_at;
4195
 
                error_code ec;
4196
 
                boost::weak_ptr<torrent> self(shared_from_this());
4197
 
                m_tracker_timer.expires_at(m_next_tracker_announce, ec);
4198
 
                m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1));
4199
 
        }
4200
 
 
4201
 
        void torrent::start_announcing()
4202
 
        {
4203
 
                if (is_paused()) return;
4204
 
                // if we don't have metadata, we need to announce
4205
 
                // before checking files, to get peers to
4206
 
                // request the metadata from
4207
 
                if (!m_files_checked && valid_metadata()) return;
4208
 
                if (m_announcing) return;
4209
 
 
4210
 
                m_announcing = true;
4211
 
 
4212
 
                if (!m_trackers.empty())
4213
 
                {
4214
 
                        // tell the tracker that we're back
4215
 
                        m_start_sent = false;
4216
 
                        m_stat.clear();
4217
 
                        announce_with_tracker();
4218
 
                }
4219
 
 
4220
 
                // private torrents are never announced on LSD
4221
 
                // or on DHT, we don't need this timer.
4222
 
                if (!m_torrent_file->is_valid() || !m_torrent_file->priv())
4223
 
                {
4224
 
                        error_code ec;
4225
 
                        boost::weak_ptr<torrent> self(shared_from_this());
4226
 
                        m_lsd_announce_timer.expires_from_now(seconds(1), ec);
4227
 
                        m_lsd_announce_timer.async_wait(
4228
 
                                bind(&torrent::on_lsd_announce_disp, self, _1));
4229
 
                }
4230
 
        }
4231
 
 
4232
 
        void torrent::stop_announcing()
4233
 
        {
4234
 
                if (!m_announcing) return;
4235
 
 
4236
 
                error_code ec;
4237
 
                m_lsd_announce_timer.cancel(ec);
4238
 
                m_tracker_timer.cancel(ec);
4239
 
 
4240
 
                m_announcing = false;
4241
 
 
4242
 
                if (!m_trackers.empty())
4243
 
                        announce_with_tracker(tracker_request::stopped);
4244
 
        }
4245
 
 
4246
 
        void torrent::second_tick(stat& accumulator, float tick_interval)
4247
 
        {
4248
 
                INVARIANT_CHECK;
4249
 
 
4250
 
#ifndef TORRENT_DISABLE_EXTENSIONS
4251
 
                for (extension_list_t::iterator i = m_extensions.begin()
4252
 
                        , end(m_extensions.end()); i != end; ++i)
4253
 
                {
4254
 
#ifndef BOOST_NO_EXCEPTIONS
4255
 
                        try {
4256
 
#endif
4257
 
                                (*i)->tick();
4258
 
#ifndef BOOST_NO_EXCEPTIONS
4259
 
                        } catch (std::exception&) {}
4260
 
#endif
4261
 
                }
4262
 
#endif
4263
 
 
4264
 
                if (is_paused())
4265
 
                {
4266
 
                        // let the stats fade out to 0
4267
 
                        m_stat.second_tick(tick_interval);
4268
 
                        return;
4269
 
                }
4270
 
 
4271
 
                time_duration since_last_tick = microsec(tick_interval * 1000000L);
4272
 
                if (is_seed()) m_seeding_time += since_last_tick;
4273
 
                m_active_time += since_last_tick;
4274
 
 
4275
 
                // ---- WEB SEEDS ----
4276
 
 
4277
 
                // re-insert urls that are to be retrieds into the m_web_seeds
4278
 
                typedef std::map<std::string, ptime>::iterator iter_t;
4279
 
                for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
4280
 
                {
4281
 
                        iter_t erase_element = i++;
4282
 
                        if (erase_element->second <= time_now())
4283
 
                        {
4284
 
                                m_web_seeds.insert(erase_element->first);
4285
 
                                m_web_seeds_next_retry.erase(erase_element);
4286
 
                        }
4287
 
                }
4288
 
 
4289
 
                // if we have everything we want we don't need to connect to any web-seed
4290
 
                if (!is_finished() && !m_web_seeds.empty() && m_files_checked)
4291
 
                {
4292
 
                        // keep trying web-seeds if there are any
4293
 
                        // first find out which web seeds we are connected to
4294
 
                        std::set<std::string> web_seeds;
4295
 
                        for (peer_iterator i = m_connections.begin();
4296
 
                                i != m_connections.end(); ++i)
4297
 
                        {
4298
 
                                web_peer_connection* p
4299
 
                                        = dynamic_cast<web_peer_connection*>(*i);
4300
 
                                if (!p) continue;
4301
 
                                web_seeds.insert(p->url());
4302
 
                        }
4303
 
 
4304
 
                        for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
4305
 
                                , end(m_resolving_web_seeds.end()); i != end; ++i)
4306
 
                                web_seeds.insert(web_seeds.begin(), *i);
4307
 
 
4308
 
                        // from the list of available web seeds, subtract the ones we are
4309
 
                        // already connected to.
4310
 
                        std::vector<std::string> not_connected_web_seeds;
4311
 
                        std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
4312
 
                                , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
4313
 
 
4314
 
                        // connect to all of those that we aren't connected to
4315
 
                        std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
4316
 
                                , bind(&torrent::connect_to_url_seed, this, _1));
4317
 
                }
4318
 
                
4319
 
                for (peer_iterator i = m_connections.begin();
4320
 
                        i != m_connections.end();)
4321
 
                {
4322
 
                        peer_connection* p = *i;
4323
 
                        ++i;
4324
 
                        p->calc_ip_overhead();
4325
 
                        m_stat += p->statistics();
4326
 
                        // updates the peer connection's ul/dl bandwidth
4327
 
                        // resource requests
4328
 
#ifndef BOOST_NO_EXCEPTIONS
4329
 
                        try
4330
 
                        {
4331
 
#endif
4332
 
                                p->second_tick(tick_interval);
4333
 
#ifndef BOOST_NO_EXCEPTIONS
4334
 
                        }
4335
 
                        catch (std::exception& e)
4336
 
                        {
4337
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
4338
 
                                (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
4339
 
#endif
4340
 
                                p->disconnect(e.what(), 1);
4341
 
                        }
4342
 
#endif
4343
 
                }
4344
 
                accumulator += m_stat;
4345
 
                m_total_uploaded += m_stat.last_payload_uploaded();
4346
 
                m_total_downloaded += m_stat.last_payload_downloaded();
4347
 
                m_stat.second_tick(tick_interval);
4348
 
 
4349
 
                m_time_scaler--;
4350
 
                if (m_time_scaler <= 0)
4351
 
                {
4352
 
                        m_time_scaler = 10;
4353
 
                        m_policy.pulse();
4354
 
                }
4355
 
        }
4356
 
 
4357
 
        void torrent::retry_url_seed(std::string const& url)
4358
 
        {
4359
 
                m_web_seeds_next_retry[url] = time_now()
4360
 
                        + seconds(m_ses.settings().urlseed_wait_retry);
4361
 
        }
4362
 
 
4363
 
        bool torrent::try_connect_peer()
4364
 
        {
4365
 
                TORRENT_ASSERT(want_more_peers());
4366
 
                if (m_deficit_counter < 100) return false;
4367
 
                m_deficit_counter -= 100;
4368
 
                bool ret = m_policy.connect_one_peer();
4369
 
                return ret;
4370
 
        }
4371
 
 
4372
 
        void torrent::give_connect_points(int points)
4373
 
        {
4374
 
                TORRENT_ASSERT(points <= 100);
4375
 
                TORRENT_ASSERT(points > 0);
4376
 
                TORRENT_ASSERT(want_more_peers());
4377
 
                m_deficit_counter += points;
4378
 
        }
4379
 
 
4380
 
        void torrent::async_verify_piece(int piece_index, boost::function<void(int)> const& f)
4381
 
        {
4382
 
//              INVARIANT_CHECK;
4383
 
 
4384
 
                TORRENT_ASSERT(m_storage);
4385
 
                TORRENT_ASSERT(m_storage->refcount() > 0);
4386
 
                TORRENT_ASSERT(piece_index >= 0);
4387
 
                TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
4388
 
                TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces());
4389
 
#ifdef TORRENT_DEBUG
4390
 
                if (m_picker)
4391
 
                {
4392
 
                        int blocks_in_piece = m_picker->blocks_in_piece(piece_index);
4393
 
                        for (int i = 0; i < blocks_in_piece; ++i)
4394
 
                        {
4395
 
                                TORRENT_ASSERT(m_picker->num_peers(piece_block(piece_index, i)) == 0);
4396
 
                        }
4397
 
                }
4398
 
#endif
4399
 
 
4400
 
                m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
4401
 
                        , shared_from_this(), _1, _2, f));
4402
 
#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
4403
 
                check_invariant();
4404
 
#endif
4405
 
        }
4406
 
 
4407
 
        void torrent::on_piece_verified(int ret, disk_io_job const& j
4408
 
                , boost::function<void(int)> f)
4409
 
        {
4410
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4411
 
 
4412
 
                // return value:
4413
 
                // 0: success, piece passed hash check
4414
 
                // -1: disk failure
4415
 
                // -2: hash check failed
4416
 
 
4417
 
                if (ret == -1)
4418
 
                {
4419
 
                        if (alerts().should_post<file_error_alert>())
4420
 
                                alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
4421
 
                        set_error(j.str);
4422
 
                        pause();
4423
 
                }
4424
 
                f(ret);
4425
 
        }
4426
 
 
4427
 
        const tcp::endpoint& torrent::current_tracker() const
4428
 
        {
4429
 
                return m_tracker_address;
4430
 
        }
4431
 
 
4432
 
        void torrent::file_progress(std::vector<float>& fp) const
4433
 
        {
4434
 
                fp.clear();
4435
 
                fp.resize(m_torrent_file->num_files(), 1.f);
4436
 
                if (is_seed()) return;
4437
 
 
4438
 
                std::vector<size_type> progress;
4439
 
                file_progress(progress);
4440
 
                for (int i = 0; i < m_torrent_file->num_files(); ++i)
4441
 
                {
4442
 
                        file_entry const& f = m_torrent_file->file_at(i);
4443
 
                        if (f.size == 0) fp[i] = 1.f;
4444
 
                        else fp[i] = float(progress[i]) / f.size;
4445
 
                }
4446
 
        }
4447
 
 
4448
 
        void torrent::file_progress(std::vector<size_type>& fp) const
4449
 
        {
4450
 
                TORRENT_ASSERT(valid_metadata());
4451
 
        
4452
 
                fp.resize(m_torrent_file->num_files(), 0);
4453
 
 
4454
 
                if (is_seed())
4455
 
                {
4456
 
                        for (int i = 0; i < m_torrent_file->num_files(); ++i)
4457
 
                                fp[i] = m_torrent_file->files().at(i).size;
4458
 
                        return;
4459
 
                }
4460
 
                
4461
 
                TORRENT_ASSERT(has_picker());
4462
 
 
4463
 
                for (int i = 0; i < m_torrent_file->num_files(); ++i)
4464
 
                {
4465
 
                        peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
4466
 
                        size_type size = m_torrent_file->files().at(i).size;
4467
 
 
4468
 
// zero sized files are considered
4469
 
// 100% done all the time
4470
 
                        if (size == 0)
4471
 
                        {
4472
 
                                fp[i] = 0;
4473
 
                                continue;
4474
 
                        }
4475
 
 
4476
 
                        size_type done = 0;
4477
 
                        while (size > 0)
4478
 
                        {
4479
 
                                size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
4480
 
                                        - ret.start), size);
4481
 
                                if (m_picker->have_piece(ret.piece)) done += bytes_step;
4482
 
                                ++ret.piece;
4483
 
                                ret.start = 0;
4484
 
                                size -= bytes_step;
4485
 
                        }
4486
 
                        TORRENT_ASSERT(size == 0);
4487
 
 
4488
 
                        fp[i] = done;
4489
 
                }
4490
 
 
4491
 
                const std::vector<piece_picker::downloading_piece>& q
4492
 
                        = m_picker->get_download_queue();
4493
 
 
4494
 
                for (std::vector<piece_picker::downloading_piece>::const_iterator
4495
 
                        i = q.begin(), end(q.end()); i != end; ++i)
4496
 
                {
4497
 
                        size_type offset = size_type(i->index) * m_torrent_file->piece_length();
4498
 
                        torrent_info::file_iterator file = m_torrent_file->file_at_offset(offset);
4499
 
                        int file_index = file - m_torrent_file->begin_files();
4500
 
                        int num_blocks = m_picker->blocks_in_piece(i->index);
4501
 
                        piece_picker::block_info const* info = i->info;
4502
 
                        for (int k = 0; k < num_blocks; ++k)
4503
 
                        {
4504
 
                                TORRENT_ASSERT(file != m_torrent_file->end_files());
4505
 
                                TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4506
 
                                        + k * m_block_size);
4507
 
                                TORRENT_ASSERT(offset < m_torrent_file->total_size());
4508
 
                                while (offset >= file->offset + file->size)
4509
 
                                {
4510
 
                                        ++file;
4511
 
                                        ++file_index;
4512
 
                                }
4513
 
                                TORRENT_ASSERT(file != m_torrent_file->end_files());
4514
 
 
4515
 
                                size_type block_size = m_block_size;
4516
 
 
4517
 
                                if (info[k].state == piece_picker::block_info::state_none)
4518
 
                                {
4519
 
                                        offset += m_block_size;
4520
 
                                        continue;
4521
 
                                }
4522
 
 
4523
 
                                if (info[k].state == piece_picker::block_info::state_requested)
4524
 
                                {
4525
 
                                        block_size = 0;
4526
 
                                        policy::peer* p = static_cast<policy::peer*>(info[k].peer);
4527
 
                                        if (p && p->connection)
4528
 
                                        {
4529
 
                                                boost::optional<piece_block_progress> pbp
4530
 
                                                        = p->connection->downloading_piece_progress();
4531
 
                                                if (pbp && pbp->piece_index == i->index && pbp->block_index == k)
4532
 
                                                        block_size = pbp->bytes_downloaded;
4533
 
                                                TORRENT_ASSERT(block_size <= m_block_size);
4534
 
                                        }
4535
 
 
4536
 
                                        if (block_size == 0)
4537
 
                                        {
4538
 
                                                offset += m_block_size;
4539
 
                                                continue;
4540
 
                                        }
4541
 
                                }
4542
 
 
4543
 
                                if (offset + block_size > file->offset + file->size)
4544
 
                                {
4545
 
                                        int left_over = m_block_size - block_size;
4546
 
                                        // split the block on multiple files
4547
 
                                        while (block_size > 0)
4548
 
                                        {
4549
 
                                                TORRENT_ASSERT(offset <= file->offset + file->size);
4550
 
                                                size_type slice = (std::min)(file->offset + file->size - offset
4551
 
                                                        , block_size);
4552
 
                                                fp[file_index] += slice;
4553
 
                                                offset += slice;
4554
 
                                                block_size -= slice;
4555
 
                                                TORRENT_ASSERT(offset <= file->offset + file->size);
4556
 
                                                if (offset == file->offset + file->size)
4557
 
                                                {
4558
 
                                                        ++file;
4559
 
                                                        ++file_index;
4560
 
                                                        if (file == m_torrent_file->end_files())
4561
 
                                                        {
4562
 
                                                                offset += block_size;
4563
 
                                                                break;
4564
 
                                                        }
4565
 
                                                }
4566
 
                                        }
4567
 
                                        offset += left_over;
4568
 
                                        TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4569
 
                                                + (k+1) * m_block_size);
4570
 
                                }
4571
 
                                else
4572
 
                                {
4573
 
                                        fp[file_index] += block_size;
4574
 
                                        offset += m_block_size;
4575
 
                                }
4576
 
                                TORRENT_ASSERT(file_index <= m_torrent_file->num_files());
4577
 
                        }
4578
 
                }
4579
 
        }
4580
 
        
4581
 
        void torrent::set_state(torrent_status::state_t s)
4582
 
        {
4583
 
#ifdef TORRENT_DEBUG
4584
 
                if (s != torrent_status::checking_files
4585
 
                        && s != torrent_status::queued_for_checking)
4586
 
                {
4587
 
                        // the only valid transition away from queued_for_checking
4588
 
                        // is to checking_files. One exception is to finished
4589
 
                        // in case all the files are marked with priority 0
4590
 
                        if (m_queued_for_checking)
4591
 
                        {
4592
 
                                std::vector<int> pieces;
4593
 
                                m_picker->piece_priorities(pieces);
4594
 
                                // make sure all pieces have priority 0
4595
 
                                TORRENT_ASSERT(std::count(pieces.begin(), pieces.end(), 0) == pieces.size());
4596
 
                        }
4597
 
                }
4598
 
                if (s == torrent_status::seeding)
4599
 
                        TORRENT_ASSERT(is_seed());
4600
 
                if (s == torrent_status::finished)
4601
 
                        TORRENT_ASSERT(is_finished());
4602
 
                if (s == torrent_status::downloading && m_state == torrent_status::finished)
4603
 
                        TORRENT_ASSERT(!is_finished());
4604
 
#endif
4605
 
 
4606
 
                if (m_state == s) return;
4607
 
                m_state = s;
4608
 
                if (m_ses.m_alerts.should_post<state_changed_alert>())
4609
 
                        m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s));
4610
 
        }
4611
 
 
4612
 
        torrent_status torrent::status() const
4613
 
        {
4614
 
                INVARIANT_CHECK;
4615
 
 
4616
 
                ptime now = time_now();
4617
 
 
4618
 
                torrent_status st;
4619
 
 
4620
 
                st.has_incoming = m_has_incoming;
4621
 
                st.error = m_error;
4622
 
 
4623
 
                if (m_last_scrape == min_time())
4624
 
                {
4625
 
                        st.last_scrape = -1;
4626
 
                }
4627
 
                else
4628
 
                {
4629
 
                        st.last_scrape = total_seconds(now - m_last_scrape);
4630
 
                }
4631
 
                st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size();
4632
 
                st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size();
4633
 
 
4634
 
                st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
4635
 
                        , !boost::bind(&peer_connection::is_connecting, _1));
4636
 
 
4637
 
                st.list_peers = m_policy.num_peers();
4638
 
                st.list_seeds = m_policy.num_seeds();
4639
 
                st.connect_candidates = m_policy.num_connect_candidates();
4640
 
                st.seed_rank = seed_rank(m_ses.m_settings);
4641
 
 
4642
 
                st.all_time_upload = m_total_uploaded;
4643
 
                st.all_time_download = m_total_downloaded;
4644
 
 
4645
 
                st.active_time = total_seconds(m_active_time);
4646
 
                st.seeding_time = total_seconds(m_seeding_time);
4647
 
 
4648
 
                st.storage_mode = m_storage_mode;
4649
 
 
4650
 
                st.num_complete = m_complete;
4651
 
                st.num_incomplete = m_incomplete;
4652
 
                st.paused = m_paused;
4653
 
                boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
4654
 
                TORRENT_ASSERT(st.total_wanted_done >= 0);
4655
 
                TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4656
 
 
4657
 
                // payload transfer
4658
 
                st.total_payload_download = m_stat.total_payload_download();
4659
 
                st.total_payload_upload = m_stat.total_payload_upload();
4660
 
 
4661
 
                // total transfer
4662
 
                st.total_download = m_stat.total_payload_download()
4663
 
                        + m_stat.total_protocol_download();
4664
 
                st.total_upload = m_stat.total_payload_upload()
4665
 
                        + m_stat.total_protocol_upload();
4666
 
 
4667
 
                // failed bytes
4668
 
                st.total_failed_bytes = m_total_failed_bytes;
4669
 
                st.total_redundant_bytes = m_total_redundant_bytes;
4670
 
 
4671
 
                // transfer rate
4672
 
                st.download_rate = m_stat.download_rate();
4673
 
                st.upload_rate = m_stat.upload_rate();
4674
 
                st.download_payload_rate = m_stat.download_payload_rate();
4675
 
                st.upload_payload_rate = m_stat.upload_payload_rate();
4676
 
 
4677
 
                st.next_announce = boost::posix_time::seconds(
4678
 
                        total_seconds(next_announce() - now));
4679
 
                if (st.next_announce.is_negative() || is_paused())
4680
 
                        st.next_announce = boost::posix_time::seconds(0);
4681
 
 
4682
 
                st.announce_interval = boost::posix_time::seconds(m_duration);
4683
 
 
4684
 
                if (m_last_working_tracker >= 0)
4685
 
                {
4686
 
                        st.current_tracker
4687
 
                                = m_trackers[m_last_working_tracker].url;
4688
 
                }
4689
 
 
4690
 
                st.num_uploads = m_num_uploads;
4691
 
                st.uploads_limit = m_max_uploads;
4692
 
                st.num_connections = int(m_connections.size());
4693
 
                st.connections_limit = m_max_connections;
4694
 
                // if we don't have any metadata, stop here
4695
 
 
4696
 
                st.state = m_state;
4697
 
                // for backwards compatibility
4698
 
                if (st.state == torrent_status::checking_resume_data)
4699
 
                        st.state = torrent_status::queued_for_checking;
4700
 
 
4701
 
                if (!valid_metadata())
4702
 
                {
4703
 
                        st.state = torrent_status::downloading_metadata;
4704
 
                        st.progress = m_progress;
4705
 
                        st.block_size = 0;
4706
 
                        return st;
4707
 
                }
4708
 
 
4709
 
                st.block_size = block_size();
4710
 
 
4711
 
                // fill in status that depends on metadata
4712
 
 
4713
 
                st.total_wanted = m_torrent_file->total_size();
4714
 
                TORRENT_ASSERT(st.total_wanted >= 0);
4715
 
                TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length()
4716
 
                        * (m_torrent_file->num_pieces() - 1));
4717
 
 
4718
 
                if (m_picker.get() && (m_picker->num_filtered() > 0
4719
 
                        || m_picker->num_have_filtered() > 0))
4720
 
                {
4721
 
                        int num_filtered_pieces = m_picker->num_filtered()
4722
 
                                + m_picker->num_have_filtered();
4723
 
                        int last_piece_index = m_torrent_file->num_pieces() - 1;
4724
 
                        if (m_picker->piece_priority(last_piece_index) == 0)
4725
 
                        {
4726
 
                                st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
4727
 
                                --num_filtered_pieces;
4728
 
                        }
4729
 
                        
4730
 
                        st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length();
4731
 
                }
4732
 
 
4733
 
                TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
4734
 
 
4735
 
                if (m_state == torrent_status::checking_files)
4736
 
                        st.progress = m_progress;
4737
 
                else if (st.total_wanted == 0) st.progress = 1.f;
4738
 
                else st.progress = st.total_wanted_done
4739
 
                        / static_cast<float>(st.total_wanted);
4740
 
 
4741
 
                if (has_picker())
4742
 
                {
4743
 
                        int num_pieces = m_picker->num_pieces();
4744
 
                        st.pieces.resize(num_pieces, false);
4745
 
                        for (int i = 0; i < num_pieces; ++i)
4746
 
                                if (m_picker->have_piece(i)) st.pieces.set_bit(i);
4747
 
                }
4748
 
                st.num_pieces = num_have();
4749
 
                st.num_seeds = num_seeds();
4750
 
                if (m_picker.get())
4751
 
                        st.distributed_copies = m_picker->distributed_copies();
4752
 
                else
4753
 
                        st.distributed_copies = -1;
4754
 
                return st;
4755
 
        }
4756
 
 
4757
 
        void torrent::add_redundant_bytes(int b)
4758
 
        {
4759
 
                TORRENT_ASSERT(b > 0);
4760
 
                m_total_redundant_bytes += b;
4761
 
                m_ses.add_redundant_bytes(b);
4762
 
        }
4763
 
 
4764
 
        void torrent::add_failed_bytes(int b)
4765
 
        {
4766
 
                TORRENT_ASSERT(b > 0);
4767
 
                m_total_failed_bytes += b;
4768
 
                m_ses.add_failed_bytes(b);
4769
 
        }
4770
 
 
4771
 
        int torrent::num_seeds() const
4772
 
        {
4773
 
                INVARIANT_CHECK;
4774
 
 
4775
 
                return (int)std::count_if(m_connections.begin(), m_connections.end()
4776
 
                        , boost::bind(&peer_connection::is_seed, _1));
4777
 
        }
4778
 
 
4779
 
        void torrent::tracker_request_timed_out(
4780
 
                tracker_request const& r)
4781
 
        {
4782
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4783
 
 
4784
 
                INVARIANT_CHECK;
4785
 
 
4786
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4787
 
                debug_log("*** tracker timed out");
4788
 
#endif
4789
 
 
4790
 
                if (r.kind == tracker_request::announce_request)
4791
 
                {
4792
 
                        if (m_ses.m_alerts.should_post<tracker_error_alert>())
4793
 
                        {
4794
 
                                m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4795
 
                                        , m_failed_trackers + 1, 0, r.url, "tracker timed out"));
4796
 
                        }
4797
 
                }
4798
 
                else if (r.kind == tracker_request::scrape_request)
4799
 
                {
4800
 
                        if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4801
 
                        {
4802
 
                                m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle()
4803
 
                                        , r.url, "tracker timed out"));
4804
 
                        }
4805
 
                }
4806
 
 
4807
 
                if (r.kind == tracker_request::announce_request)
4808
 
                        try_next_tracker(r);
4809
 
        }
4810
 
 
4811
 
        // TODO: with some response codes, we should just consider
4812
 
        // the tracker as a failure and not retry
4813
 
        // it anymore
4814
 
        void torrent::tracker_request_error(tracker_request const& r
4815
 
                , int response_code, const std::string& str)
4816
 
        {
4817
 
                session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4818
 
 
4819
 
                INVARIANT_CHECK;
4820
 
 
4821
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4822
 
                debug_log(std::string("*** tracker error: ") + str);
4823
 
#endif
4824
 
                if (r.kind == tracker_request::announce_request)
4825
 
                {
4826
 
                        if (m_ses.m_alerts.should_post<tracker_error_alert>())
4827
 
                        {
4828
 
                                m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4829
 
                                        , m_failed_trackers + 1, response_code, r.url, str));
4830
 
                        }
4831
 
                }
4832
 
                else if (r.kind == tracker_request::scrape_request)
4833
 
                {
4834
 
                        if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4835
 
                        {
4836
 
                                m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
4837
 
                        }
4838
 
                }
4839
 
 
4840
 
                if (r.kind == tracker_request::announce_request)
4841
 
                        try_next_tracker(r);
4842
 
        }
4843
 
 
4844
 
 
4845
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4846
 
        void torrent::debug_log(const std::string& line)
4847
 
        {
4848
 
                (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
4849
 
        }
4850
 
#endif
4851
 
 
4852
 
}
4853