From b7e3c6b3dfe7f4a9958cc79b31f6b1a5a8ff006d Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Mon, 13 Aug 2007 09:28:29 +0000 Subject: [PATCH] Sync libtorrent to trunk. Start of columns menu. --- deluge/ui/gtkui/glade/torrent_menu.glade | 99 +----------- deluge/ui/gtkui/listview.py | 18 ++- deluge/ui/gtkui/torrentview.py | 5 +- libtorrent/include/libtorrent/alert_types.hpp | 57 +++++++ .../include/libtorrent/bandwidth_manager.hpp | 64 +++++--- libtorrent/include/libtorrent/config.hpp | 5 + .../include/libtorrent/disk_io_thread.hpp | 4 + libtorrent/include/libtorrent/entry.hpp | 2 +- .../include/libtorrent/peer_connection.hpp | 15 +- libtorrent/include/libtorrent/peer_info.hpp | 4 + .../include/libtorrent/piece_picker.hpp | 7 +- libtorrent/include/libtorrent/policy.hpp | 2 + libtorrent/include/libtorrent/session.hpp | 5 +- .../include/libtorrent/session_settings.hpp | 9 ++ libtorrent/include/libtorrent/torrent.hpp | 2 + .../include/libtorrent/torrent_handle.hpp | 16 +- .../include/libtorrent/torrent_info.hpp | 4 +- libtorrent/include/libtorrent/xml_parse.hpp | 146 ++++++++++++++++-- libtorrent/src/Makefile.am | 2 +- libtorrent/src/connection_queue.cpp | 2 +- libtorrent/src/disk_io_thread.cpp | 5 + libtorrent/src/file.cpp | 16 +- libtorrent/src/lsd.cpp | 1 - libtorrent/src/peer_connection.cpp | 80 ++++++++-- libtorrent/src/piece_picker.cpp | 70 +++++++-- libtorrent/src/policy.cpp | 53 ++++++- libtorrent/src/session_impl.cpp | 32 +--- libtorrent/src/storage.cpp | 21 ++- libtorrent/src/torrent.cpp | 37 +++-- libtorrent/src/torrent_handle.cpp | 3 + libtorrent/src/upnp.cpp | 48 ++++-- libtorrent/src/ut_pex.cpp | 50 +++--- libtorrent/src/web_peer_connection.cpp | 9 +- 33 files changed, 613 insertions(+), 280 deletions(-) diff --git a/deluge/ui/gtkui/glade/torrent_menu.glade b/deluge/ui/gtkui/glade/torrent_menu.glade index 774cc3716..b371e68d3 100644 --- a/deluge/ui/gtkui/glade/torrent_menu.glade +++ b/deluge/ui/gtkui/glade/torrent_menu.glade @@ -35,6 +35,11 @@ + + + True + + True @@ -69,7 +74,7 @@ - + True @@ -90,97 +95,5 @@ - - - True - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Queue - True - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Top - True - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-goto-top - 1 - - - - - - - True - _Up - True - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-go-up - 1 - - - - - - - True - _Down - True - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-go-down - 1 - - - - - - - True - _Bottom - True - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-goto-bottom - 1 - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-sort-ascending - 1 - - - - diff --git a/deluge/ui/gtkui/listview.py b/deluge/ui/gtkui/listview.py index 253d81bd3..0dec730cc 100644 --- a/deluge/ui/gtkui/listview.py +++ b/deluge/ui/gtkui/listview.py @@ -82,6 +82,7 @@ class ListView: def __init__(self, name, column_indices): self.name = name self.column_indices = column_indices + self.column = None def __init__(self, treeview_widget=None): log.debug("ListView initialized..") @@ -113,6 +114,13 @@ class ListView: else: return self.columns[name].column_indices[0] + def create_checklist_menu(self): + menu = gtk.Menu() + for column in self.columns.values(): + menuitem = gtk.CheckMenuItem(column.name) + menu.append(menuitem) + return menu + def create_new_liststore(self): # Create a new liststore with added column and move the data from the # old one to the new one. @@ -158,6 +166,7 @@ class ListView: column.set_reorderable(True) column.set_visible(visible) self.treeview.append_column(column) + self.columns[header].column = column return True @@ -194,7 +203,8 @@ class ListView: column.set_min_width(10) column.set_reorderable(True) self.treeview.append_column(column) - + self.columns[header].column = column + return True def add_progress_column(self, header): @@ -221,7 +231,8 @@ class ListView: column.set_min_width(10) column.set_reorderable(True) self.treeview.append_column(column) - + self.columns[header].column = column + return True def add_texticon_column(self, header): @@ -251,5 +262,6 @@ class ListView: column.add_attribute(render, 'text', self.columns[header].column_indices[1]) self.treeview.append_column(column) - + self.columns[header].column = column + return True diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index eb58085a2..1d6fdc03c 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -80,6 +80,9 @@ class TorrentView(listview.ListView): listview.cell_data_ratio, [float]) + self.window.main_glade.get_widget("menu_columns").set_submenu( + self.create_checklist_menu()) + ### Connect Signals ### # Connect to the 'button-press-event' to know when to bring up the # torrent menu popup. @@ -100,7 +103,7 @@ class TorrentView(listview.ListView): "eta"] status = functions.get_torrent_status(self.core, torrent_id, status_keys) - + # Set values for each column in the row self.liststore.set_value(row, diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 7b32d2502..48491bca4 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -184,6 +184,63 @@ namespace libtorrent { return std::auto_ptr(new torrent_finished_alert(*this)); } }; + struct TORRENT_EXPORT piece_finished_alert: torrent_alert + { + piece_finished_alert( + const torrent_handle& h + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , piece_index(piece_num) + { assert(piece_index >= 0);} + + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new piece_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_finished_alert: torrent_alert + { + block_finished_alert( + const torrent_handle& h + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , block_index(block_num) + , piece_index(piece_num) + { assert(block_index >= 0 && piece_index >= 0);} + + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_downloading_alert: torrent_alert + { + block_downloading_alert( + const torrent_handle& h + , std::string& speedmsg + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , peer_speedmsg(speedmsg) + , block_index(block_num) + , piece_index(piece_num) + { assert(block_index >= 0 && piece_index >= 0);} + + std::string peer_speedmsg; + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_downloading_alert(*this)); } + }; + struct TORRENT_EXPORT storage_moved_alert: torrent_alert { storage_moved_alert(torrent_handle const& h, std::string const& path) diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 4df9d4f2f..75e1f1d4e 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -90,47 +90,47 @@ struct bandwidth_limit { static const int inf = boost::integer_traits::const_max; - bandwidth_limit() + bandwidth_limit() throw() : m_quota_left(0) , m_local_limit(inf) , m_current_rate(0) {} - void throttle(int limit) + void throttle(int limit) throw() { m_local_limit = limit; } - int throttle() const + int throttle() const throw() { return m_local_limit; } - void assign(int amount) + void assign(int amount) throw() { assert(amount > 0); m_current_rate += amount; m_quota_left += amount; } - void use_quota(int amount) + void use_quota(int amount) throw() { assert(amount <= m_quota_left); m_quota_left -= amount; } - int quota_left() const + int quota_left() const throw() { return (std::max)(m_quota_left, 0); } - void expire(int amount) + void expire(int amount) throw() { assert(amount >= 0); m_current_rate -= amount; } - int max_assignable() const + int max_assignable() const throw() { if (m_local_limit == inf) return inf; if (m_local_limit <= m_current_rate) return 0; @@ -160,7 +160,7 @@ private: }; template -T clamp(T val, T ceiling, T floor) +T clamp(T val, T ceiling, T floor) throw() { assert(ceiling >= floor); if (val >= ceiling) return ceiling; @@ -171,7 +171,7 @@ T clamp(T val, T ceiling, T floor) template struct bandwidth_manager { - bandwidth_manager(io_service& ios, int channel) + bandwidth_manager(io_service& ios, int channel) throw() : m_ios(ios) , m_history_timer(m_ios) , m_limit(bandwidth_limit::inf) @@ -179,14 +179,14 @@ struct bandwidth_manager , m_channel(channel) {} - void throttle(int limit) + void throttle(int limit) throw() { mutex_t::scoped_lock l(m_mutex); assert(limit >= 0); m_limit = limit; } - int throttle() const + int throttle() const throw() { mutex_t::scoped_lock l(m_mutex); return m_limit; @@ -197,7 +197,7 @@ struct bandwidth_manager // this is used by web seeds void request_bandwidth(intrusive_ptr peer , int blk - , bool non_prioritized) + , bool non_prioritized) throw() { INVARIANT_CHECK; assert(blk > 0); @@ -257,8 +257,11 @@ struct bandwidth_manager private: - void add_history_entry(history_entry const& e) try + void add_history_entry(history_entry const& e) throw() { +#ifndef NDEBUG + try { +#endif INVARIANT_CHECK; m_history.push_front(e); m_current_quota += e.amount; @@ -268,11 +271,17 @@ private: m_history_timer.expires_at(e.expires_at); m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); +#ifndef NDEBUG + } + catch (std::exception&) { assert(false); } +#endif } - catch (std::exception&) { assert(false); } - void on_history_expire(asio::error_code const& e) try + void on_history_expire(asio::error_code const& e) throw() { +#ifndef NDEBUG + try { +#endif INVARIANT_CHECK; if (e) return; @@ -303,14 +312,20 @@ private: // means we can hand out more (in case there // are still consumers in line) if (!m_queue.empty()) hand_out_bandwidth(); +#ifndef NDEBUG + } + catch (std::exception&) + { + assert(false); + } +#endif } - catch (std::exception&) - { - assert(false); - }; - void hand_out_bandwidth() try + void hand_out_bandwidth() throw() { +#ifndef NDEBUG + try { +#endif INVARIANT_CHECK; ptime now(time_now()); @@ -404,9 +419,12 @@ private: add_history_entry(history_entry( qe.peer, t, hand_out_amount, now + bw_window_size)); } +#ifndef NDEBUG + } + catch (std::exception& e) + { assert(false); }; +#endif } - catch (std::exception& e) - { assert(false); }; typedef boost::mutex mutex_t; diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp index c8d86955e..b36d4da22 100755 --- a/libtorrent/include/libtorrent/config.hpp +++ b/libtorrent/include/libtorrent/config.hpp @@ -37,6 +37,8 @@ POSSIBILITY OF SUCH DAMAGE. #if defined(__GNUC__) && __GNUC__ >= 4 +#define TORRENT_DEPRECATED __attribute__ ((deprecated)) + # if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED) # define TORRENT_EXPORT __attribute__ ((visibility("default"))) # else @@ -61,6 +63,9 @@ POSSIBILITY OF SUCH DAMAGE. # define TORRENT_EXPORT #endif +#ifndef TORRENT_DEPRECATED +#define TORRENT_DEPRECATED +#endif #endif // TORRENT_CONFIG_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index aff0930e4..16ee0bca4 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -111,6 +111,10 @@ namespace libtorrent // memory pool for read and write operations boost::pool<> m_pool; +#ifndef NDEBUG + int m_block_size; +#endif + // thread for performing blocking disk io operations boost::thread m_disk_io_thread; }; diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index a1eba5324..59e29803d 100755 --- a/libtorrent/include/libtorrent/entry.hpp +++ b/libtorrent/include/libtorrent/entry.hpp @@ -59,7 +59,7 @@ POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include #include #include diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index d32d250fc..31bcde94a 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -74,10 +74,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_type.hpp" #include "libtorrent/intrusive_ptr_base.hpp" -// TODO: each time a block is 'taken over' -// from another peer. That peer must be given -// a chance to become not-interested. - namespace libtorrent { class torrent; @@ -395,9 +391,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_ENCRYPTION buffer::interval wr_recv_buffer() { -#if defined _SECURE_SCL && _SECURE_SCL > 0 if (m_recv_buffer.empty()) return buffer::interval(0,0); -#endif return buffer::interval(&m_recv_buffer[0] , &m_recv_buffer[0] + m_recv_pos); } @@ -405,9 +399,7 @@ namespace libtorrent buffer::const_interval receive_buffer() const { -#if defined _SECURE_SCL && _SECURE_SCL > 0 if (m_recv_buffer.empty()) return buffer::const_interval(0,0); -#endif return buffer::const_interval(&m_recv_buffer[0] , &m_recv_buffer[0] + m_recv_pos); } @@ -646,7 +638,8 @@ namespace libtorrent bool m_queued; // these are true when there's a asynchronous write - // or read operation running. + // or read operation in progress. Or an asyncronous bandwidth + // request is in progress. bool m_writing; bool m_reading; @@ -701,6 +694,10 @@ namespace libtorrent // a timestamp when the remote download rate // was last updated ptime m_remote_dl_update; + + // the number of bytes send to the disk-io + // thread that hasn't yet been completely written. + int m_outstanding_writing_bytes; #ifndef NDEBUG public: diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index f8ee2feb6..15ad34a7a 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -144,6 +144,10 @@ namespace libtorrent // approximate peer download rate int remote_dl_rate; + + // number of bytes this peer has in + // the disk write queue + int pending_disk_bytes; }; } diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 136e71c63..54df003ef 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -163,7 +163,9 @@ namespace libtorrent void we_have(int index); // sets the priority of a piece. - void set_piece_priority(int index, int prio); + // returns true if the priority was changed from 0 to non-0 + // or vice versa + bool set_piece_priority(int index, int prio); // returns the priority for the piece at 'index' int piece_priority(int index) const; @@ -215,6 +217,9 @@ namespace libtorrent void mark_as_finished(piece_block block, void* peer); int num_peers(piece_block block) const; + // returns information about the given piece + void piece_info(int index, piece_picker::downloading_piece& st) const; + // if a piece had a hash-failure, it must be restored and // made available for redownloading void restore_piece(int index); diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp index e087ccb75..6c976d047 100755 --- a/libtorrent/include/libtorrent/policy.hpp +++ b/libtorrent/include/libtorrent/policy.hpp @@ -110,6 +110,8 @@ namespace libtorrent // the peer is not interested in our pieces void not_interested(peer_connection& c); + void ip_filter_updated(); + #ifndef NDEBUG bool has_connection(const peer_connection* p); diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index 52ec62cdb..38206f32c 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -144,14 +144,15 @@ namespace libtorrent , int block_size = 16 * 1024 , storage_constructor_type sc = default_storage_constructor); - // TODO: deprecated, this is for backwards compatibility only + // ==== deprecated, this is for backwards compatibility only + // instead, use one of the other add_torrent overloads torrent_handle add_torrent( entry const& e , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true , int block_size = 16 * 1024 - , storage_constructor_type sc = default_storage_constructor) + , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED { return add_torrent(torrent_info(e), save_path, resume_data , compact_mode, block_size, sc); diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 783492227..ebc30eae3 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -108,6 +108,7 @@ namespace libtorrent , unchoke_interval(20) , num_want(200) , initial_picker_threshold(4) + , max_outstanding_disk_bytes_per_connection(64 * 1024) #ifndef TORRENT_DISABLE_DHT , use_dht_as_fallback(true) #endif @@ -251,6 +252,14 @@ namespace libtorrent // random pieces instead of rarest first. int initial_picker_threshold; + // the maximum number of bytes a connection may have + // pending in the disk write queue before its download + // rate is being throttled. This prevents fast downloads + // to slow medias to allocate more and more memory + // indefinitely. This should be set to at least 32 kB + // to not completely disrupt normal downloads. + int max_outstanding_disk_bytes_per_connection; + #ifndef TORRENT_DISABLE_DHT // while this is true, the dht will note be used unless the // tracker is online diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index bed076fe9..2eef2656b 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -175,6 +175,8 @@ namespace libtorrent boost::tuples::tuple bytes_done() const; size_type quantized_bytes_done() const; + void ip_filter_updated() { m_policy->ip_filter_updated(); } + void pause(); void resume(); bool is_paused() const { return m_paused; } diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index a4c8af923..3f7ae5bcc 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -241,6 +241,12 @@ namespace libtorrent enum { max_blocks_per_piece = 256 }; int piece_index; int blocks_in_piece; + // the number of blocks in the finished state + int finished; + // the number of blocks in the writing state + int writing; + // the number of blocks in the requested state + int requested; block_info blocks[max_blocks_per_piece]; enum state_t { none, slow, medium, fast }; state_t piece_state; @@ -290,13 +296,13 @@ namespace libtorrent // marks the piece with the given index as filtered // it will not be downloaded - void filter_piece(int index, bool filter) const; - void filter_pieces(std::vector const& pieces) const; - bool is_piece_filtered(int index) const; - std::vector filtered_pieces() const; + void filter_piece(int index, bool filter) const TORRENT_DEPRECATED; + void filter_pieces(std::vector const& pieces) const TORRENT_DEPRECATED; + bool is_piece_filtered(int index) const TORRENT_DEPRECATED; + std::vector filtered_pieces() const TORRENT_DEPRECATED; // marks the file with the given index as filtered // it will not be downloaded - void filter_files(std::vector const& files) const; + void filter_files(std::vector const& files) const TORRENT_DEPRECATED; // ================ end deprecation ============ diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index e52024255..a2d6c4ef9 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #ifdef _MSC_VER #pragma warning(push, 1) @@ -146,7 +147,8 @@ namespace libtorrent const std::string& name() const { assert(m_piece_length > 0); return m_name; } // ------- start deprecation ------- - void print(std::ostream& os) const; +// this functionaily will be removed in a future version + void print(std::ostream& os) const TORRENT_DEPRECATED; // ------- end deprecation ------- bool is_valid() const { return m_piece_length > 0; } diff --git a/libtorrent/include/libtorrent/xml_parse.hpp b/libtorrent/include/libtorrent/xml_parse.hpp index c3aeddad7..67ae406f0 100644 --- a/libtorrent/include/libtorrent/xml_parse.hpp +++ b/libtorrent/include/libtorrent/xml_parse.hpp @@ -33,11 +33,25 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_XML_PARSE_HPP #define TORRENT_XML_PARSE_HPP +#include + namespace libtorrent { - const int xml_start_tag = 0; - const int xml_end_tag = 1; - const int xml_string = 2; + enum + { + xml_start_tag, + xml_end_tag, + xml_empty_tag, + xml_declaration_tag, + xml_string, + xml_attribute, + xml_comment, + xml_parse_error + }; + + // callback(int type, char const* name, char const* val) + // str2 is only used for attributes. name is element or attribute + // name and val is attribute value template void xml_parse(char* p, char* end, CallbackType callback) @@ -45,6 +59,8 @@ namespace libtorrent for(;p != end; ++p) { char const* start = p; + char const* val_start = 0; + int token; // look for tag start for(; *p != '<' && p != end; ++p); @@ -55,39 +71,135 @@ namespace libtorrent assert(*p == '<'); *p = 0; } - callback(xml_string, start); + token = xml_string; + callback(token, start, val_start); if (p != end) *p = '<'; } - + if (p == end) break; // skip '<' ++p; - // parse the name of the tag. Ignore attributes - for (start = p; p != end && *p != '>'; ++p) - { - // terminate the string at the first space - // to ignore tag attributes - if (*p == ' ') *p = 0; - } + // parse the name of the tag. + for (start = p; p != end && *p != '>' && !std::isspace(*p); ++p); + + char* tag_name_end = p; + + // skip the attributes for now + for (; p != end && *p != '>'; ++p); // parse error - if (p == end) break; + if (p == end) + { + token = xml_parse_error; + start = "unexpected end of file"; + callback(token, start, val_start); + break; + } assert(*p == '>'); - *p = 0; + // save the character that terminated the tag name + // it could be both '>' and ' '. + char save = *tag_name_end; + *tag_name_end = 0; + char* tag_end = p; if (*start == '/') { ++start; - callback(xml_end_tag, start); + token = xml_end_tag; + callback(token, start, val_start); + } + else if (*(p-1) == '/') + { + *(p-1) = 0; + token = xml_empty_tag; + callback(token, start, val_start); + *(p-1) = '/'; + tag_end = p - 1; + } + else if (*start == '?' && *(p-1) == '?') + { + *(p-1) = 0; + ++start; + token = xml_declaration_tag; + callback(token, start, val_start); + *(p-1) = '?'; + tag_end = p - 1; + } + else if (start + 5 < p && memcmp(start, "!--", 3) == 0 && memcmp(p-2, "--", 2) == 0) + { + start += 3; + *(p-2) = 0; + token = xml_comment; + callback(token, start, val_start); + *(p-2) = '-'; + tag_end = p - 2; } else { - callback(xml_start_tag, start); + token = xml_start_tag; + callback(token, start, val_start); + } + + *tag_name_end = save; + + // parse attributes + for (char* i = tag_name_end; i < tag_end; ++i) + { + // find start of attribute name + for (; i != tag_end && std::isspace(*i); ++i); + if (i == tag_end) break; + start = i; + // find end of attribute name + for (; i != tag_end && *i != '=' && !std::isspace(*i); ++i); + char* name_end = i; + + // look for equality sign + for (; i != tag_end && *i != '='; ++i); + + if (i == tag_end) + { + token = xml_parse_error; + val_start = 0; + start = "garbage inside element brackets"; + callback(token, start, val_start); + break; + } + + ++i; + for (; i != tag_end && std::isspace(*i); ++i); + // check for parse error (values must be quoted) + if (i == tag_end || (*i != '\'' && *i != '\"')) + { + token = xml_parse_error; + val_start = 0; + start = "unquoted attribute value"; + callback(token, start, val_start); + break; + } + char quote = *i; + ++i; + val_start = i; + for (; i != tag_end && *i != quote; ++i); + // parse error (missing end quote) + if (i == tag_end) + { + token = xml_parse_error; + val_start = 0; + start = "missing end quote on attribute"; + callback(token, start, val_start); + break; + } + save = *i; + *i = 0; + *name_end = 0; + token = xml_attribute; + callback(token, start, val_start); + *name_end = '='; + *i = save; } - *p = '>'; } } diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am index ef834018b..fabe68b65 100644 --- a/libtorrent/src/Makefile.am +++ b/libtorrent/src/Makefile.am @@ -95,6 +95,6 @@ $(top_srcdir)/include/libtorrent/version.hpp libtorrent_la_LDFLAGS = $(LDFLAGS) -release @VERSION@ libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ -AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@ +AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@ -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION AM_LDFLAGS= $(LDFLAGS) -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ diff --git a/libtorrent/src/connection_queue.cpp b/libtorrent/src/connection_queue.cpp index 473a92920..859205ed0 100644 --- a/libtorrent/src/connection_queue.cpp +++ b/libtorrent/src/connection_queue.cpp @@ -159,7 +159,7 @@ namespace libtorrent ptime next_expire = max_time(); ptime now = time_now(); for (std::list::iterator i = m_queue.begin(); - i != m_queue.end();) + !m_queue.empty() && i != m_queue.end();) { if (i->connecting && i->expires < now) { diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index b02ab0012..6bc357506 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -41,6 +41,9 @@ namespace libtorrent : m_abort(false) , m_queue_buffer_size(0) , m_pool(block_size) +#ifndef NDEBUG + , m_block_size(block_size) +#endif , m_disk_io_thread(boost::ref(*this)) {} @@ -192,6 +195,7 @@ namespace libtorrent } else { + assert(j.buffer_size <= m_block_size); ret = j.storage->read_impl(j.buffer, j.piece, j.offset , j.buffer_size); @@ -201,6 +205,7 @@ namespace libtorrent break; case disk_io_job::write: assert(j.buffer); + assert(j.buffer_size <= m_block_size); j.storage->write_impl(j.buffer, j.piece, j.offset , j.buffer_size); diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp index 515406a46..3d568d1f7 100755 --- a/libtorrent/src/file.cpp +++ b/libtorrent/src/file.cpp @@ -248,11 +248,17 @@ namespace libtorrent void set_size(size_type s) { size_type pos = tell(); - seek(s - 1); - char dummy = 0; - read(&dummy, 1); - seek(s - 1); - write(&dummy, 1); + // Only set size if current file size not equals s. + // 2 as "m" argument is to be sure seek() sets SEEK_END on + // all compilers. + if(s != seek(0, 2)) + { + seek(s - 1); + char dummy = 0; + read(&dummy, 1); + seek(s - 1); + write(&dummy, 1); + } seek(pos); } diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index b73e407bc..76f25548d 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/lsd.hpp" #include "libtorrent/io.hpp" #include "libtorrent/http_tracker_connection.hpp" -#include "libtorrent/xml_parse.hpp" #include #include #include diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 7dbef4381..b73e32896 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -116,6 +116,7 @@ namespace libtorrent , m_remote_bytes_dled(0) , m_remote_dl_rate(0) , m_remote_dl_update(time_now()) + , m_outstanding_writing_bytes(0) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -189,6 +190,7 @@ namespace libtorrent , m_remote_bytes_dled(0) , m_remote_dl_rate(0) , m_remote_dl_update(time_now()) + , m_outstanding_writing_bytes(0) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -936,7 +938,8 @@ namespace libtorrent && r.start < t->torrent_file().piece_size(r.piece) && r.length > 0 && r.length + r.start <= t->torrent_file().piece_size(r.piece) - && m_peer_interested) + && m_peer_interested + && r.length <= t->block_size()) { #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() @@ -961,7 +964,8 @@ namespace libtorrent "i: " << m_peer_interested << " | " "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "n: " << t->torrent_file().num_pieces() << " | " - "h: " << t->have_piece(r.piece) << " ]\n"; + "h: " << t->have_piece(r.piece) << " | " + "block_limit: " << t->block_size() << " ]\n"; #endif ++m_num_invalid_requests; @@ -1150,6 +1154,8 @@ namespace libtorrent fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete , self(), _1, _2, p, t)); + m_outstanding_writing_bytes += p.length; + assert(!m_reading); picker.mark_as_writing(block_finished, peer_info_struct()); } @@ -1158,6 +1164,16 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + m_outstanding_writing_bytes -= p.length; + assert(m_outstanding_writing_bytes >= 0); + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << " *** on_disk_write_complete() " << p.length << "\n"; +#endif + // in case the outstanding bytes just dropped down + // to allow to receive more data + setup_receive(); + if (ret == -1 || !t) { if (!t) @@ -1183,6 +1199,11 @@ namespace libtorrent assert(p.start == j.offset); piece_block block_finished(p.piece, p.start / t->block_size()); picker.mark_as_finished(block_finished, peer_info_struct()); + if (t->alerts().should_post(alert::info)) + { + t->alerts().post_alert(block_finished_alert(t->get_handle(), + block_finished.block_index, block_finished.piece_index, "block finished")); + } if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired()) { @@ -1290,11 +1311,29 @@ namespace libtorrent piece_picker::piece_state_t state; peer_speed_t speed = peer_speed(); - if (speed == fast) state = piece_picker::fast; - else if (speed == medium) state = piece_picker::medium; - else state = piece_picker::slow; + std::string speedmsg; + if (speed == fast) + { + speedmsg = "fast"; + state = piece_picker::fast; + } + else if (speed == medium) + { + speedmsg = "medium"; + state = piece_picker::medium; + } + else + { + speedmsg = "slow"; + state = piece_picker::slow; + } t->picker().mark_as_downloading(block, peer_info_struct(), state); + if (t->alerts().should_post(alert::info)) + { + t->alerts().post_alert(block_downloading_alert(t->get_handle(), + speedmsg, block.block_index, block.piece_index, "block downloading")); + } m_request_queue.push_back(block); } @@ -1642,6 +1681,7 @@ namespace libtorrent p.payload_up_speed = statistics().upload_payload_rate(); p.pid = pid(); p.ip = remote(); + p.pending_disk_bytes = m_outstanding_writing_bytes; #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES p.country[0] = m_country[0]; @@ -2015,11 +2055,13 @@ namespace libtorrent m_bandwidth_limit[channel].assign(amount); if (channel == upload_channel) { + assert(m_writing); m_writing = false; setup_send(); } else if (channel == download_channel) { + assert(m_reading); m_reading = false; setup_receive(); } @@ -2067,10 +2109,11 @@ namespace libtorrent (*m_logger) << "req bandwidth [ " << upload_channel << " ]\n"; #endif + assert(!m_writing); // peers that we are not interested in are non-prioritized + m_writing = true; t->request_bandwidth(upload_channel, self() , !(is_interesting() && !has_peer_choked())); - m_writing = true; } return; } @@ -2116,6 +2159,9 @@ namespace libtorrent INVARIANT_CHECK; +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "setup_receive: reading = " << m_reading << "\n"; +#endif if (m_reading) return; shared_ptr t = m_torrent.lock(); @@ -2130,8 +2176,8 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << "req bandwidth [ " << download_channel << " ]\n"; #endif - t->request_bandwidth(download_channel, self(), m_non_prioritized); m_reading = true; + t->request_bandwidth(download_channel, self(), m_non_prioritized); } return; } @@ -2144,7 +2190,7 @@ namespace libtorrent if (!m_ignore_bandwidth_limits && max_receive > quota_left) max_receive = quota_left; - assert(max_receive > 0); + if (max_receive == 0) return; assert(m_recv_pos >= 0); assert(m_packet_size > 0); @@ -2242,10 +2288,7 @@ namespace libtorrent m_recv_pos += bytes_transferred; assert(m_recv_pos <= int(m_recv_buffer.size())); - { - INVARIANT_CHECK; - on_receive(error, bytes_transferred); - } + on_receive(error, bytes_transferred); assert(m_packet_size > 0); @@ -2322,9 +2365,17 @@ namespace libtorrent { INVARIANT_CHECK; - return (m_bandwidth_limit[download_channel].quota_left() > 0 + bool ret = (m_bandwidth_limit[download_channel].quota_left() > 0 || m_ignore_bandwidth_limits) - && !m_connecting; + && !m_connecting + && m_outstanding_writing_bytes < + m_ses.settings().max_outstanding_disk_bytes_per_connection; + +#if defined(TORRENT_VERBOSE_LOGGING) + (*m_logger) << "*** can_read() " << ret << " reading: " << m_reading << "\n"; +#endif + + return ret; } void peer_connection::connect(int ticket) @@ -2649,6 +2700,7 @@ namespace libtorrent (*m_logger) << time_now_string() << " ==> KEEPALIVE\n"; #endif + m_last_sent = time_now(); write_keepalive(); } diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 61f3544b7..ddc2c2f5a 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -129,6 +129,35 @@ namespace libtorrent } } + void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const + { + TORRENT_PIECE_PICKER_INVARIANT_CHECK; + + assert(index >= 0); + assert(index < int(m_piece_map.size())); + + if (m_piece_map[index].downloading) + { + std::vector::const_iterator piece = std::find_if( + m_downloads.begin(), m_downloads.end() + , bind(&downloading_piece::index, _1) == index); + assert(piece != m_downloads.end()); + st = *piece; + st.info = 0; + return; + } + st.info = 0; + st.index = index; + st.writing = 0; + st.requested = 0; + if (m_piece_map[index].have()) + { + st.finished = blocks_in_piece(index); + return; + } + st.finished = 0; + } + void piece_picker::set_sequenced_download_threshold( int sequenced_download_threshold) { @@ -196,7 +225,8 @@ namespace libtorrent int block_index = num_downloads * m_blocks_per_piece; if (int(m_block_info.size()) < block_index + m_blocks_per_piece) { - block_info* base = &m_block_info[0]; + block_info* base = 0; + if (!m_block_info.empty()) base = &m_block_info[0]; m_block_info.resize(block_index + m_blocks_per_piece); if (!m_downloads.empty() && &m_block_info[0] != base) { @@ -605,9 +635,10 @@ namespace libtorrent void piece_picker::sort_piece(std::vector::iterator dp) { assert(m_piece_map[dp->index].downloading); + if (dp == m_downloads.begin()) return; int complete = dp->writing + dp->finished; for (std::vector::iterator i = dp, j(dp-1); - i != m_downloads.begin(); --i, --j) + i != m_downloads.begin() && j != m_downloads.begin(); --i, --j) { assert(j >= m_downloads.begin()); if (j->finished + j->writing >= complete) return; @@ -935,7 +966,7 @@ namespace libtorrent } - void piece_picker::set_piece_priority(int index, int new_piece_priority) + bool piece_picker::set_piece_priority(int index, int new_piece_priority) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(new_piece_priority >= 0); @@ -946,16 +977,18 @@ namespace libtorrent piece_pos& p = m_piece_map[index]; // if the priority isn't changed, don't do anything - if (new_piece_priority == int(p.piece_priority)) return; + if (new_piece_priority == int(p.piece_priority)) return false; int prev_priority = p.priority(m_sequenced_download_threshold); + bool ret = false; if (new_piece_priority == piece_pos::filter_priority && p.piece_priority != piece_pos::filter_priority) { // the piece just got filtered if (p.have()) ++m_num_have_filtered; else ++m_num_filtered; + ret = true; } else if (new_piece_priority != piece_pos::filter_priority && p.piece_priority == piece_pos::filter_priority) @@ -963,6 +996,7 @@ namespace libtorrent // the piece just got unfiltered if (p.have()) --m_num_have_filtered; else --m_num_filtered; + ret = true; } assert(m_num_filtered >= 0); assert(m_num_have_filtered >= 0); @@ -970,7 +1004,7 @@ namespace libtorrent p.piece_priority = new_piece_priority; int new_priority = p.priority(m_sequenced_download_threshold); - if (new_priority == prev_priority) return; + if (new_priority == prev_priority) return false; if (prev_priority == 0) { @@ -980,6 +1014,7 @@ namespace libtorrent { move(prev_priority, p.index); } + return ret; } int piece_picker::piece_priority(int index) const @@ -1051,8 +1086,12 @@ namespace libtorrent // downloaded to std::vector backup_blocks; + // When prefer_whole_pieces is set (usually set when downloading from + // fast peers) the partial pieces will not be prioritized, but actually + // ignored as long as possible. All blocks found in downloading + // pieces are regarded as backup blocks bool ignore_downloading_pieces = false; - if (!prefer_whole_pieces) + if (prefer_whole_pieces) { std::vector downloading_pieces; downloading_pieces.reserve(m_downloads.size()); @@ -1061,8 +1100,8 @@ namespace libtorrent { downloading_pieces.push_back(i->index); } - num_blocks = add_interesting_blocks(downloading_pieces, pieces - , interesting_blocks, backup_blocks, num_blocks + add_interesting_blocks(downloading_pieces, pieces + , backup_blocks, backup_blocks, num_blocks , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); ignore_downloading_pieces = true; } @@ -1072,10 +1111,6 @@ namespace libtorrent // has filled the interesting_blocks with num_blocks // blocks. - // When prefer_whole_pieces is set (usually set when downloading from - // fast peers) the partial pieces will not be prioritized, but actually - // ignored as long as possible. - // +1 is to ignore pieces that no peer has. The bucket with index 0 contains // pieces that 0 other peers have. bucket will point to a bucket with // pieces with the same priority. It will be iterated in priority @@ -1128,8 +1163,7 @@ namespace libtorrent if (!backup_blocks.empty()) interesting_blocks.insert(interesting_blocks.end() - , backup_blocks.begin(), backup_blocks.begin() - + (std::min)(num_blocks, (int)backup_blocks.size())); + , backup_blocks.begin(), backup_blocks.end()); } void piece_picker::clear_peer(void* peer) @@ -1216,7 +1250,6 @@ namespace libtorrent // will be picked. if (prefer_whole_pieces && !exclusive) { - if (int(backup_blocks.size()) >= num_blocks) continue; for (int j = 0; j < num_blocks_in_piece; ++j) { block_info const& info = p->info[j]; @@ -1251,7 +1284,6 @@ namespace libtorrent && !exclusive_active && !ignore_speed_categories) { - if (int(backup_blocks.size()) >= num_blocks) continue; backup_blocks.push_back(piece_block(*i, j)); continue; } @@ -1264,9 +1296,9 @@ namespace libtorrent // to look for blocks until we have num_blocks // blocks that have not been requested from any // other peer. - interesting_blocks.push_back(piece_block(*i, j)); if (p->info[j].state == block_info::state_none) { + interesting_blocks.push_back(piece_block(*i, j)); // we have found a block that's free to download num_blocks--; // if we prefer whole pieces, continue picking from this @@ -1275,6 +1307,10 @@ namespace libtorrent assert(num_blocks >= 0); if (num_blocks == 0) return num_blocks; } + else + { + backup_blocks.push_back(piece_block(*i, j)); + } } assert(num_blocks >= 0 || prefer_whole_pieces); if (num_blocks < 0) num_blocks = 0; diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 2444deeb7..572f48d35 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -249,7 +249,7 @@ namespace libtorrent // with the other's, to see if we should abort another // peer_connection in favour of this one std::vector busy_pieces; - busy_pieces.reserve(10); + busy_pieces.reserve(num_requests); for (std::vector::iterator i = interesting_pieces.begin(); i != interesting_pieces.end(); ++i) @@ -272,6 +272,8 @@ namespace libtorrent // by somebody else. request it from this peer // and return c.add_request(*i); + assert(p.num_peers(*i) == 1); + assert(p.is_requested(*i)); num_requests--; } @@ -286,6 +288,8 @@ namespace libtorrent return; } + // if all blocks has the same number of peers on them + // we want to pick a random block std::random_shuffle(busy_pieces.begin(), busy_pieces.end()); // find the block with the fewest requests to it @@ -293,7 +297,11 @@ namespace libtorrent busy_pieces.begin(), busy_pieces.end() , bind(&piece_picker::num_peers, boost::cref(p), _1) < bind(&piece_picker::num_peers, boost::cref(p), _2)); - +#ifndef NDEBUG + piece_picker::downloading_piece st; + p.piece_info(i->piece_index, st); + assert(st.requested + st.finished + st.writing == p.blocks_in_piece(i->piece_index)); +#endif c.add_request(*i); c.send_block_requests(); } @@ -304,6 +312,47 @@ namespace libtorrent , m_available_free_upload(0) , m_last_optimistic_disconnect(min_time()) { assert(t); } + + // disconnects and removes all peers that are now filtered + void policy::ip_filter_updated() + { + aux::session_impl& ses = m_torrent->session(); + piece_picker* p = 0; + if (m_torrent->has_picker()) + p = &m_torrent->picker(); + for (std::list::iterator i = m_peers.begin() + , end(m_peers.end()); i != end;) + { + if ((ses.m_ip_filter.access(i->ip.address()) & ip_filter::blocked) == 0) + { + ++i; + continue; + } + + if (i->connection) + { + i->connection->disconnect(); + if (ses.m_alerts.should_post(alert::info)) + { + ses.m_alerts.post_alert(peer_blocked_alert(i->ip.address() + , "disconnected blocked peer")); + } + assert(i->connection == 0 + || i->connection->peer_info_struct() == 0); + } + else + { + if (ses.m_alerts.should_post(alert::info)) + { + ses.m_alerts.post_alert(peer_blocked_alert(i->ip.address() + , "blocked peer removed from peer list")); + } + } + if (p) p->clear_peer(&(*i)); + m_peers.erase(i++); + } + } + // finds the peer that has the worst download rate // and returns it. May return 0 if all peers are // choked. diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index f4323586c..81f48a3ce 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -613,29 +613,9 @@ namespace detail // Close connections whose endpoint is filtered // by the new ip-filter - for (session_impl::connection_map::iterator i - = m_connections.begin(); i != m_connections.end();) - { - tcp::endpoint sender; - try { sender = i->first->remote_endpoint(); } - catch (std::exception&) { sender = i->second->remote(); } - if (m_ip_filter.access(sender.address()) & ip_filter::blocked) - { -#if defined(TORRENT_VERBOSE_LOGGING) - (*i->second->m_logger) << "*** CONNECTION FILTERED\n"; -#endif - if (m_alerts.should_post(alert::info)) - { - m_alerts.post_alert(peer_blocked_alert(sender.address() - , "peer connection closed by IP filter")); - } - - session_impl::connection_map::iterator j = i; - ++i; - j->second->disconnect(); - } - else ++i; - } + for (torrent_map::iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; ++i) + i->second->ip_filter_updated(); } void session_impl::set_settings(session_settings const& s) @@ -1921,13 +1901,15 @@ namespace detail int session_impl::upload_rate_limit() const { mutex_t::scoped_lock l(m_mutex); - return m_bandwidth_manager[peer_connection::upload_channel]->throttle(); + int ret = m_bandwidth_manager[peer_connection::upload_channel]->throttle(); + return ret == std::numeric_limits::max() ? -1 : ret; } int session_impl::download_rate_limit() const { mutex_t::scoped_lock l(m_mutex); - return m_bandwidth_manager[peer_connection::download_channel]->throttle(); + int ret = m_bandwidth_manager[peer_connection::download_channel]->throttle(); + return ret == std::numeric_limits::max() ? -1 : ret; } void session_impl::start_lsd() diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 793f95365..b23a2e858 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -981,7 +981,7 @@ namespace libtorrent return true; #endif -#if defined(__APPLE__) || defined(__linux__) +#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) // find the last existing directory of the save path fs::path query_path = p; while (!query_path.empty() && !exists(query_path)) @@ -1019,6 +1019,7 @@ namespace libtorrent return true; } + // workaround for bugs in Mac OS X where zero run is not reported if (!strcmp(fsinfo.f_fstypename, "hfs") || !strcmp(fsinfo.f_fstypename, "ufs")) return true; @@ -1026,7 +1027,7 @@ namespace libtorrent return false; #endif -#if defined(__linux__) +#if defined(__linux__) || defined(__FreeBSD__) struct statfs buf; int err = statfs(query_path.native_directory_string().c_str(), &buf); if (err == 0) @@ -1044,6 +1045,7 @@ namespace libtorrent case 0x52345362: // Reiser4 case 0x58465342: // XFS case 0x65735546: // NTFS-3G + case 0x19540119: // UFS2 return true; } } @@ -1125,6 +1127,7 @@ namespace libtorrent j.piece = r.piece; j.offset = r.start; j.buffer_size = r.length; + assert(r.length <= 16 * 1024); m_io_thread.add_job(j, handler); } @@ -1569,16 +1572,12 @@ namespace libtorrent } if (m_unallocated_slots.empty()) - { m_state = state_create_files; - return false; - } - - if (m_compact_mode) - { + else if (m_compact_mode) m_state = state_create_files; - return false; - } + else + m_state = state_allocating; + return false; } m_state = state_full_check; @@ -1598,7 +1597,7 @@ namespace libtorrent | | | v | +------------+ - | | allocating | + |->| allocating | | +------------+ | | | v diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 39f29172f..13309c1e7 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -831,6 +831,11 @@ namespace libtorrent if (passed_hash_check) { + if (m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(piece_finished_alert(get_handle() + , index, "piece finished")); + } // the following call may cause picker to become invalid // in case we just became a seed announce_piece(index); @@ -1104,7 +1109,7 @@ namespace libtorrent void torrent::set_piece_priority(int index, int priority) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(valid_metadata()); if (is_seed()) return; @@ -1114,13 +1119,13 @@ namespace libtorrent assert(index >= 0); assert(index < m_torrent_file.num_pieces()); - m_picker->set_piece_priority(index, priority); - update_peer_interest(); + bool filter_updated = m_picker->set_piece_priority(index, priority); + if (filter_updated) update_peer_interest(); } int torrent::piece_priority(int index) const { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(valid_metadata()); if (is_seed()) return 1; @@ -1144,14 +1149,15 @@ namespace libtorrent assert(m_picker.get()); int index = 0; + bool filter_updated = false; for (std::vector::const_iterator i = pieces.begin() , end(pieces.end()); i != end; ++i, ++index) { assert(*i >= 0); assert(*i <= 7); - m_picker->set_piece_priority(index, *i); + filter_updated |= m_picker->set_piece_priority(index, *i); } - update_peer_interest(); + if (filter_updated) update_peer_interest(); } void torrent::piece_priorities(std::vector& pieces) const @@ -1653,17 +1659,26 @@ namespace libtorrent }; #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES + namespace + { + unsigned long swap_bytes(unsigned long a) + { + return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | (a << 24); + } + } + void torrent::resolve_peer_country(boost::intrusive_ptr const& p) const { if (m_resolving_country || p->has_country() || p->is_connecting() || p->is_queued() - || p->in_handshake()) return; + || p->in_handshake() + || p->remote().address().is_v6()) return; m_resolving_country = true; - tcp::resolver::query q(boost::lexical_cast(p->remote().address()) - + ".zz.countries.nerd.dk", "0"); + asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong())); + tcp::resolver::query q(reversed.to_string() + ".zz.countries.nerd.dk", "0"); m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p))); } @@ -2325,15 +2340,11 @@ namespace libtorrent torrent_handle torrent::get_handle() const { - INVARIANT_CHECK; - return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash()); } session_settings const& torrent::settings() const { -// INVARIANT_CHECK; - return m_ses.settings(); } diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 10e1172fa..4538e66e8 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -773,6 +773,9 @@ namespace libtorrent partial_piece_info pi; pi.piece_state = (partial_piece_info::state_t)i->state; pi.blocks_in_piece = p.blocks_in_piece(i->index); + pi.finished = (int)i->finished; + pi.writing = (int)i->writing; + pi.requested = (int)i->requested; int piece_size = t->torrent_file().piece_size(i->index); for (int j = 0; j < pi.blocks_in_piece; ++j) { diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index c60725e9d..aefff41b1 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -62,9 +62,10 @@ namespace libtorrent { if (a.is_v6()) return false; address_v4 a4 = a.to_v4(); - return ((a4.to_ulong() & 0xff000000) == 0x0a000000 - || (a4.to_ulong() & 0xfff00000) == 0xac100000 - || (a4.to_ulong() & 0xffff0000) == 0xc0a80000); + unsigned long ip = a4.to_ulong(); + return ((ip & 0xff000000) == 0x0a000000 + || (ip & 0xfff00000) == 0xac100000 + || (ip & 0xffff0000) == 0xc0a80000); } address_v4 guess_local_address(asio::io_service& ios) @@ -658,7 +659,7 @@ void upnp::on_upnp_xml(asio::error_code const& e d.upnp_connection.reset(); } - if (e) + if (e && e != asio::error::eof) { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() @@ -671,7 +672,16 @@ void upnp::on_upnp_xml(asio::error_code const& e { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== incomplete http message" << std::endl; + << " <== error while fetching control url: incomplete http message" << std::endl; +#endif + return; + } + + if (p.status_code() != 200) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " <== error while fetching control url: " << p.message() << std::endl; #endif return; } @@ -790,7 +800,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e d.upnp_connection.reset(); } - if (e) + if (e && e != asio::error::eof) { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() @@ -823,12 +833,22 @@ void upnp::on_upnp_map_response(asio::error_code const& e { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== incomplete http message" << std::endl; + << " <== error while adding portmap: incomplete http message" << std::endl; #endif m_devices.erase(d); return; } + if (p.status_code() != 200) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " <== error while adding portmap: " << p.message() << std::endl; +#endif + m_devices.erase(d); + return; + } + error_code_parse_state s; xml_parse((char*)p.get_body().begin, (char*)p.get_body().end , m_strand.wrap(bind(&find_error_code, _1, _2, boost::ref(s)))); @@ -932,7 +952,7 @@ void upnp::on_upnp_unmap_response(asio::error_code const& e d.upnp_connection.reset(); } - if (e) + if (e && e != asio::error::eof) { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() @@ -944,11 +964,21 @@ void upnp::on_upnp_unmap_response(asio::error_code const& e { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== incomplete http message" << std::endl; + << " <== error while deleting portmap: incomplete http message" << std::endl; #endif return; } + if (p.status_code() != 200) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " <== error while deleting portmap: " << p.message() << std::endl; +#endif + m_devices.erase(d); + return; + } + #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() << " <== unmap response: " << std::string(p.get_body().begin, p.get_body().end) diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp index 41df77475..18cbf6c2f 100644 --- a/libtorrent/src/ut_pex.cpp +++ b/libtorrent/src/ut_pex.cpp @@ -197,39 +197,41 @@ namespace libtorrent { namespace } virtual bool on_extended(int length, int msg, buffer::const_interval body) - try { if (msg != extension_index) return false; if (m_message_index == 0) return false; if (length > 500 * 1024) - throw protocol_error("ut peer exchange message larger than 500 kB"); + throw protocol_error("uT peer exchange message larger than 500 kB"); if (body.left() < length) return true; - entry pex_msg = bdecode(body.begin, body.end); - std::string const& peers = pex_msg["added"].string(); - std::string const& peer_flags = pex_msg["added.f"].string(); - - int num_peers = peers.length() / 6; - char const* in = peers.c_str(); - char const* fin = peer_flags.c_str(); - - if (int(peer_flags.size()) != num_peers) - return true; - - peer_id pid(0); - policy& p = m_torrent.get_policy(); - for (int i = 0; i < num_peers; ++i) + try { - tcp::endpoint adr = detail::read_v4_endpoint(in); - char flags = detail::read_uint8(fin); - p.peer_from_tracker(adr, pid, peer_info::pex, flags); - } - return true; - } - catch (std::exception&) - { + entry pex_msg = bdecode(body.begin, body.end); + std::string const& peers = pex_msg["added"].string(); + std::string const& peer_flags = pex_msg["added.f"].string(); + + int num_peers = peers.length() / 6; + char const* in = peers.c_str(); + char const* fin = peer_flags.c_str(); + + if (int(peer_flags.size()) != num_peers) + return true; + + peer_id pid(0); + policy& p = m_torrent.get_policy(); + for (int i = 0; i < num_peers; ++i) + { + tcp::endpoint adr = detail::read_v4_endpoint(in); + char flags = detail::read_uint8(fin); + p.peer_from_tracker(adr, pid, peer_info::pex, flags); + } + } + catch (std::exception&) + { + throw protocol_error("invalid uT peer exchange message"); + } return true; } diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 5a8acf512..6c6745f30 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -315,7 +315,14 @@ namespace libtorrent { INVARIANT_CHECK; - if (error) return; + if (error) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "*** web_peer_connection error: " + << error.message() << "\n"; +#endif + return; + } boost::shared_ptr t = associated_torrent().lock(); assert(t);