00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef TORRENT_TORRENT_HPP_INCLUDE
00034 #define TORRENT_TORRENT_HPP_INCLUDE
00035
00036 #include <algorithm>
00037 #include <vector>
00038 #include <set>
00039 #include <list>
00040 #include <iostream>
00041
00042 #ifdef _MSC_VER
00043 #pragma warning(push, 1)
00044 #endif
00045
00046 #include <boost/limits.hpp>
00047 #include <boost/filesystem/path.hpp>
00048 #include <boost/date_time/posix_time/posix_time.hpp>
00049 #include <boost/tuple/tuple.hpp>
00050 #include <boost/enable_shared_from_this.hpp>
00051 #include <boost/scoped_ptr.hpp>
00052 #include <boost/intrusive_ptr.hpp>
00053
00054 #ifdef _MSC_VER
00055 #pragma warning(pop)
00056 #endif
00057
00058 #include "libtorrent/torrent_handle.hpp"
00059 #include "libtorrent/entry.hpp"
00060 #include "libtorrent/torrent_info.hpp"
00061 #include "libtorrent/socket.hpp"
00062 #include "libtorrent/policy.hpp"
00063 #include "libtorrent/tracker_manager.hpp"
00064 #include "libtorrent/stat.hpp"
00065 #include "libtorrent/alert.hpp"
00066 #include "libtorrent/resource_request.hpp"
00067 #include "libtorrent/piece_picker.hpp"
00068 #include "libtorrent/config.hpp"
00069 #include "libtorrent/escape_string.hpp"
00070 #include "libtorrent/bandwidth_manager.hpp"
00071
00072 namespace libtorrent
00073 {
00074 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00075 struct logger;
00076 #endif
00077
00078 class piece_manager;
00079 struct torrent_plugin;
00080
00081 namespace aux
00082 {
00083 struct session_impl;
00084 struct piece_checker_data;
00085 }
00086
00087
00088
00089
00090 class TORRENT_EXPORT torrent: public request_callback
00091 , public boost::enable_shared_from_this<torrent>
00092 {
00093 public:
00094
00095 torrent(
00096 aux::session_impl& ses
00097 , aux::checker_impl& checker
00098 , torrent_info const& tf
00099 , boost::filesystem::path const& save_path
00100 , tcp::endpoint const& net_interface
00101 , bool compact_mode
00102 , int block_size
00103 , session_settings const& s);
00104
00105
00106
00107 torrent(
00108 aux::session_impl& ses
00109 , aux::checker_impl& checker
00110 , char const* tracker_url
00111 , sha1_hash const& info_hash
00112 , char const* name
00113 , boost::filesystem::path const& save_path
00114 , tcp::endpoint const& net_interface
00115 , bool compact_mode
00116 , int block_size
00117 , session_settings const& s);
00118
00119 ~torrent();
00120
00121 #ifndef TORRENT_DISABLE_EXTENSIONS
00122 void add_extension(boost::shared_ptr<torrent_plugin>);
00123 #endif
00124
00125
00126
00127 void init();
00128
00129
00130
00131
00132
00133 void abort();
00134 bool is_aborted() const { return m_abort; }
00135
00136
00137
00138 bool is_allocating() const;
00139
00140 session_settings const& settings() const;
00141
00142 aux::session_impl& session() { return m_ses; }
00143
00144 void set_sequenced_download_threshold(int threshold);
00145
00146
00147
00148
00149
00150 void second_tick(stat& accumulator, float tick_interval);
00151
00152
00153 void print(std::ostream& os) const;
00154
00155 std::string name() const;
00156
00157 bool check_fastresume(aux::piece_checker_data&);
00158 std::pair<bool, float> check_files();
00159 void files_checked(std::vector<piece_picker::downloading_piece> const&
00160 unfinished_pieces);
00161
00162 stat statistics() const { return m_stat; }
00163 size_type bytes_left() const;
00164 boost::tuples::tuple<size_type, size_type> bytes_done() const;
00165 size_type quantized_bytes_done() const;
00166
00167 void pause();
00168 void resume();
00169 bool is_paused() const { return m_paused; }
00170
00171 void filter_piece(int index, bool filter);
00172 void filter_pieces(std::vector<bool> const& bitmask);
00173 bool is_piece_filtered(int index) const;
00174 void filtered_pieces(std::vector<bool>& bitmask) const;
00175
00176 void filter_files(std::vector<bool> const& files);
00177
00178 torrent_status status() const;
00179 void file_progress(std::vector<float>& fp) const;
00180
00181 void use_interface(const char* net_interface);
00182 tcp::endpoint const& get_interface() const { return m_net_interface; }
00183
00184 void connect_to_url_seed(std::string const& url);
00185 peer_connection& connect_to_peer(tcp::endpoint const& a);
00186
00187 void set_ratio(float ratio)
00188 { assert(ratio >= 0.0f); m_ratio = ratio; }
00189
00190 float ratio() const
00191 { return m_ratio; }
00192
00193 void resolve_countries(bool r)
00194 { m_resolve_countries = r; }
00195
00196 bool resolving_countries() const { return m_resolve_countries; }
00197
00198
00199
00200
00201 bandwidth_limit m_bandwidth_limit[2];
00202
00203 void request_bandwidth(int channel
00204 , boost::intrusive_ptr<peer_connection> p
00205 , bool non_prioritized);
00206
00207 void expire_bandwidth(int channel, int amount);
00208 void assign_bandwidth(int channel, int amount);
00209
00210 int bandwidth_throttle(int channel) const;
00211
00212
00213
00214
00215
00216
00217 void add_url_seed(std::string const& url)
00218 { m_web_seeds.insert(url); }
00219
00220 void remove_url_seed(std::string const& url)
00221 { m_web_seeds.erase(url); }
00222
00223
00224
00225
00226 void attach_peer(peer_connection* p);
00227
00228
00229
00230
00231 void remove_peer(peer_connection* p);
00232
00233 peer_connection* connection_for(tcp::endpoint const& a)
00234 {
00235 peer_iterator i = m_connections.find(a);
00236 if (i == m_connections.end()) return 0;
00237 return i->second;
00238 }
00239
00240
00241 int num_peers() const { return (int)m_connections.size(); }
00242 int num_seeds() const;
00243
00244 typedef std::map<tcp::endpoint, peer_connection*>::iterator peer_iterator;
00245 typedef std::map<tcp::endpoint, peer_connection*>::const_iterator const_peer_iterator;
00246
00247 const_peer_iterator begin() const { return m_connections.begin(); }
00248 const_peer_iterator end() const { return m_connections.end(); }
00249
00250 peer_iterator begin() { return m_connections.begin(); }
00251 peer_iterator end() { return m_connections.end(); }
00252
00253 void resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const;
00254
00255
00256
00257
00258
00259
00260
00261
00262 virtual void tracker_response(
00263 tracker_request const& r
00264 , std::vector<peer_entry>& e, int interval
00265 , int complete, int incomplete);
00266 virtual void tracker_request_timed_out(
00267 tracker_request const& r);
00268 virtual void tracker_request_error(tracker_request const& r
00269 , int response_code, const std::string& str);
00270 virtual void tracker_warning(std::string const& msg);
00271
00272
00273
00274 tracker_request generate_tracker_request();
00275
00276
00277
00278
00279
00280
00281 std::string tracker_login() const;
00282
00283
00284
00285 boost::posix_time::ptime next_announce() const;
00286
00287
00288
00289 bool should_request();
00290
00291
00292 void force_tracker_request();
00293 void force_tracker_request(boost::posix_time::ptime);
00294
00295
00296
00297 void set_tracker_login(std::string const& name, std::string const& pw);
00298
00299
00300
00301 const tcp::endpoint& current_tracker() const;
00302
00303
00304
00305
00306
00307 bool have_piece(int index) const
00308 {
00309 assert(index >= 0 && index < (signed)m_have_pieces.size());
00310 return m_have_pieces[index];
00311 }
00312
00313 const std::vector<bool>& pieces() const
00314 { return m_have_pieces; }
00315
00316 int num_pieces() const { return m_num_pieces; }
00317
00318
00319
00320 void peer_has(int index)
00321 {
00322 if (m_picker.get())
00323 {
00324 assert(!is_seed());
00325 assert(index >= 0 && index < (signed)m_have_pieces.size());
00326 m_picker->inc_refcount(index);
00327 }
00328 #ifndef NDEBUG
00329 else
00330 {
00331 assert(is_seed());
00332 }
00333 #endif
00334 }
00335
00336
00337 void peer_lost(int index)
00338 {
00339 if (m_picker.get())
00340 {
00341 assert(!is_seed());
00342 assert(index >= 0 && index < (signed)m_have_pieces.size());
00343 m_picker->dec_refcount(index);
00344 }
00345 #ifndef NDEBUG
00346 else
00347 {
00348 assert(is_seed());
00349 }
00350 #endif
00351 }
00352
00353 int block_size() const { assert(m_block_size > 0); return m_block_size; }
00354
00355
00356
00357
00358 void announce_piece(int index);
00359
00360 void disconnect_all();
00361
00362
00363
00364
00365 void completed();
00366
00367
00368
00369 void on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
00370 , peer_id pid);
00371
00372
00373
00374 void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
00375 , std::string url, tcp::endpoint proxy);
00376
00377
00378
00379 void on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
00380 , std::string url);
00381
00382
00383
00384
00385
00386 void finished();
00387
00388 bool verify_piece(int piece_index);
00389
00390
00391
00392
00393 void piece_failed(int index);
00394 void received_redundant_data(int num_bytes)
00395 { assert(num_bytes > 0); m_total_redundant_bytes += num_bytes; }
00396
00397 bool is_seed() const
00398 {
00399 return valid_metadata()
00400 && m_num_pieces == m_torrent_file.num_pieces();
00401 }
00402
00403 boost::filesystem::path save_path() const;
00404 alert_manager& alerts() const;
00405 piece_picker& picker()
00406 {
00407 assert(m_picker.get());
00408 return *m_picker;
00409 }
00410 policy& get_policy()
00411 {
00412 assert(m_policy);
00413 return *m_policy;
00414 }
00415 piece_manager& filesystem();
00416 torrent_info const& torrent_file() const
00417 { return m_torrent_file; }
00418
00419 std::vector<announce_entry> const& trackers() const
00420 { return m_trackers; }
00421
00422 void replace_trackers(std::vector<announce_entry> const& urls);
00423
00424 torrent_handle get_handle() const;
00425
00426
00427 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00428 virtual void debug_log(const std::string& line);
00429 #endif
00430
00431
00432 #ifndef NDEBUG
00433 void check_invariant() const;
00434 #endif
00435
00436
00437
00438
00439 void distribute_resources(float tick_interval);
00440
00441 resource_request m_uploads_quota;
00442 resource_request m_connections_quota;
00443
00444 void set_peer_upload_limit(tcp::endpoint ip, int limit);
00445 void set_peer_download_limit(tcp::endpoint ip, int limit);
00446
00447 void set_upload_limit(int limit);
00448 void set_download_limit(int limit);
00449 void set_max_uploads(int limit);
00450 void set_max_connections(int limit);
00451 bool move_storage(boost::filesystem::path const& save_path);
00452
00453
00454
00455 bool ready_for_connections() const
00456 { return m_connections_initialized; }
00457 bool valid_metadata() const
00458 { return m_storage.get() != 0; }
00459
00460
00461
00462
00463
00464 void set_metadata(entry const&);
00465
00466 private:
00467
00468 void try_next_tracker();
00469 int prioritize_tracker(int tracker_index);
00470 void on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i
00471 , boost::intrusive_ptr<peer_connection> p) const;
00472 bool request_bandwidth_from_session(int channel) const;
00473
00474 torrent_info m_torrent_file;
00475
00476
00477
00478 bool m_abort;
00479
00480
00481 bool m_paused;
00482
00483
00484 bool m_just_paused;
00485
00486 tracker_request::event_t m_event;
00487
00488 void parse_response(const entry& e, std::vector<peer_entry>& peer_list);
00489
00490
00491
00492
00493 int m_block_size;
00494
00495
00496
00497
00498 boost::scoped_ptr<piece_manager> m_storage;
00499
00500
00501 boost::posix_time::ptime m_next_request;
00502
00503
00504
00505
00506
00507
00508 int m_duration;
00509
00510
00511
00512 int m_complete;
00513 int m_incomplete;
00514
00515 #ifndef NDEBUG
00516 public:
00517 #endif
00518 std::map<tcp::endpoint, peer_connection*> m_connections;
00519 #ifndef NDEBUG
00520 private:
00521 #endif
00522
00523
00524
00525 std::set<std::string> m_web_seeds;
00526
00527
00528
00529 std::set<std::string> m_resolving_web_seeds;
00530
00531
00532 mutable tcp::resolver m_host_resolver;
00533
00534
00535
00536
00537
00538 mutable bool m_resolving_country;
00539
00540
00541
00542 bool m_resolve_countries;
00543
00544 #ifndef TORRENT_DISABLE_DHT
00545 static void on_dht_announce_response_disp(boost::weak_ptr<torrent> t
00546 , std::vector<tcp::endpoint> const& peers);
00547 deadline_timer m_dht_announce_timer;
00548 void on_dht_announce(asio::error_code const& e);
00549 void on_dht_announce_response(std::vector<tcp::endpoint> const& peers);
00550 bool should_announce_dht() const;
00551 #endif
00552
00553
00554
00555 libtorrent::stat m_stat;
00556
00557
00558
00559 libtorrent::stat m_web_stat;
00560
00561
00562
00563 boost::shared_ptr<policy> m_policy;
00564
00565
00566
00567 aux::session_impl& m_ses;
00568 aux::checker_impl& m_checker;
00569
00570 boost::scoped_ptr<piece_picker> m_picker;
00571
00572
00573 std::deque<bw_queue_entry> m_bandwidth_queue[2];
00574
00575 std::vector<announce_entry> m_trackers;
00576
00577 int m_last_working_tracker;
00578 int m_currently_trying_tracker;
00579
00580
00581
00582 int m_failed_trackers;
00583
00584
00585
00586
00587 int m_time_scaler;
00588
00589
00590 std::vector<bool> m_have_pieces;
00591
00592
00593
00594
00595 int m_num_pieces;
00596
00597
00598
00599
00600 bool m_got_tracker_response;
00601
00602
00603
00604
00605 float m_ratio;
00606
00607
00608
00609 size_type m_total_failed_bytes;
00610 size_type m_total_redundant_bytes;
00611
00612 std::string m_username;
00613 std::string m_password;
00614
00615
00616
00617 tcp::endpoint m_net_interface;
00618
00619 boost::filesystem::path m_save_path;
00620
00621
00622 const bool m_compact_mode;
00623
00624
00625
00626 const int m_default_block_size;
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 bool m_connections_initialized;
00638
00639
00640
00641
00642
00643 boost::scoped_ptr<std::string> m_name;
00644
00645 session_settings const& m_settings;
00646
00647 #ifndef TORRENT_DISABLE_EXTENSIONS
00648 typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
00649 extension_list_t m_extensions;
00650 #endif
00651
00652 #ifndef NDEBUG
00653
00654
00655
00656 size_type m_initial_done;
00657 #endif
00658
00659 #ifdef TORRENT_LOGGING
00660 boost::shared_ptr<logger> m_log;
00661 boost::shared_ptr<logger> m_peer_log;
00662 int m_second_count;
00663
00664 enum { debug_bw_history_size = 10 };
00665 int m_ul_history[debug_bw_history_size];
00666 int m_dl_history[debug_bw_history_size];
00667 #endif
00668 };
00669
00670 inline boost::posix_time::ptime torrent::next_announce() const
00671 {
00672 return m_next_request;
00673 }
00674
00675 inline void torrent::force_tracker_request()
00676 {
00677 using boost::posix_time::second_clock;
00678 m_next_request = second_clock::universal_time();
00679 }
00680
00681 inline void torrent::force_tracker_request(boost::posix_time::ptime t)
00682 {
00683 namespace time = boost::posix_time;
00684 m_next_request = t;
00685 }
00686
00687 inline void torrent::set_tracker_login(
00688 std::string const& name
00689 , std::string const& pw)
00690 {
00691 m_username = name;
00692 m_password = pw;
00693 }
00694
00695 }
00696
00697 #endif // TORRENT_TORRENT_HPP_INCLUDED
00698