diff --git a/docs/extension_protocol.html b/docs/extension_protocol.html index 015bbcee5..897736e41 100644 --- a/docs/extension_protocol.html +++ b/docs/extension_protocol.html @@ -3,10 +3,130 @@ - + - +
@@ -19,8 +139,8 @@ Ludvig Strigeus, ludde@utorrent.com -
-

extension protocol for bittorrent

+
+

extension protocol for bittorrent

The intention of this protocol is to provide a simple and thin transport for extensions to the bittorrent protocol. Supporting this protocol makes it easy to add new extensions without interfering with the standard @@ -88,8 +208,8 @@ message as specified by the handshake. -

-

handshake message

+
+

handshake message

The payload of the handshake message is a bencoded dictionary. All items in the dictionary are optional. Any unknown names should be ignored by the client. All parts of the dictionary are case sensitive. @@ -140,6 +260,11 @@ known. This is a much more reliable way of identifying the client than relying on the peer id encoding. +reqq +An integer, the number of outstanding request messages +this client supports without dropping any. The default in +in libtorrent is 250. +

The handshake dictionary could also include extended handshake @@ -214,8 +339,8 @@ for the actual extensions to the bittorrent protocol and the extensions named in the example above (such as p) are just examples of possible extensions.

-
-

rationale

+
+

rationale

The reason why the extension messages' IDs would be defined in the handshake is to avoid having a global registry somewhere, where ID's are assigned global identifiers. Now the extensions have unique names.

diff --git a/docs/extension_protocol.rst b/docs/extension_protocol.rst index 22d024b8f..8eb6ea3a8 100644 --- a/docs/extension_protocol.rst +++ b/docs/extension_protocol.rst @@ -87,6 +87,10 @@ Here are two other items that an implementation may choose to support: | | This is a much more reliable way of identifying the | | | client than relying on the peer id encoding. | +-------+-----------------------------------------------------------+ +| reqq | An integer, the number of outstanding request messages | +| | this client supports without dropping any. The default in | +| | in libtorrent is 250. | ++-------+-----------------------------------------------------------+ The handshake dictionary could also include extended handshake information, such as support for encrypted headers or anything diff --git a/docs/manual.html b/docs/manual.html index 690f1210f..b3090260e 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -229,60 +229,61 @@ div.warning, div.note, div.important {
  • fingerprint
  • free functions
  • -
  • alerts
  • @@ -2459,6 +2460,18 @@ to extract a string describing a client version from its peer-id. It will recogn that have this kind of identification in the peer-id.

    +

    client_fingerprint()

    +
    +
    +boost::optional<fingerprint> client_fingerprint(peer_id const& p);
    +
    +
    +

    Returns an optional fingerprint if any can be identified from the peer id. This can be used +to automate the identification of clients. It will not be able to identifiy peers with non- +standard encodings. Only Azureus style, Shadow's style and Mainline style. This function is +declared in the header <libtorrent/identify_client.hpp>.

    +
    +

    bdecode() bencode()

    diff --git a/docs/manual.rst b/docs/manual.rst
    index 6a0c9be95..860bb85fb 100755
    --- a/docs/manual.rst
    +++ b/docs/manual.rst
    @@ -2346,6 +2346,20 @@ This function is declared in the header ````. It
     to extract a string describing a client version from its peer-id. It will recognize most clients
     that have this kind of identification in the peer-id.
     
    +
    +client_fingerprint()
    +--------------------
    +
    +	::
    +
    +		boost::optional client_fingerprint(peer_id const& p);
    +
    +Returns an optional fingerprint if any can be identified from the peer id. This can be used
    +to automate the identification of clients. It will not be able to identifiy peers with non-
    +standard encodings. Only Azureus style, Shadow's style and Mainline style. This function is
    +declared in the header ````.
    +
    +
     bdecode() bencode()
     -------------------
     
    diff --git a/include/libtorrent/debug.hpp b/include/libtorrent/debug.hpp
    index e496b583c..8aeeeb544 100755
    --- a/include/libtorrent/debug.hpp
    +++ b/include/libtorrent/debug.hpp
    @@ -67,63 +67,22 @@ namespace libtorrent
     
     	struct logger
     	{
    -		logger& operator<<(const char* t)
    -		{ assert(t); log(t); return *this; }
    -		logger& operator<<(const std::string& t)
    -		{ log(t.c_str()); return *this; }
    -		logger& operator<<(int i)
    -		{
    -			log(boost::lexical_cast(i).c_str());
    -			return *this; 
    -		}
    -		logger& operator<<(unsigned int i)
    -		{
    -			log(boost::lexical_cast(i).c_str());
    -			return *this; 
    -		}
    -		logger& operator<<(float i)
    -		{
    -			log(boost::lexical_cast(i).c_str());
    -			return *this; 
    -		}
    -
    -		logger& operator<<(char i)
    -		{
    -			char c[2];
    -			c[0] = i;
    -			c[1] = 0;
    -			log(c);
    -			return *this; 
    -		}
    -
    -		virtual void log(const char*) = 0;
    -		virtual ~logger() {}
    -	};
    -
    -	struct null_logger: libtorrent::logger
    -	{
    -	public:
    -		virtual void log(const char*) {}
    -	};
    -
    -	struct cout_logger: libtorrent::logger
    -	{
    -	public:
    -		virtual void log(const char* text) { std::cout << text; }
    -	};
    -
    -	struct file_logger: libtorrent::logger
    -	{
    -	public:
    -		file_logger(boost::filesystem::path const& filename, bool append = true)
    +		logger(boost::filesystem::path const& filename, bool append = true)
     		{
     			using namespace boost::filesystem;
     			path dir(complete("libtorrent_logs"));
     			if (!exists(dir)) create_directories(dir);
     			m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
    -			log("\n\n\n*** starting log ***\n");
    +			*this << "\n\n\n*** starting log ***\n";
    +		}
    +
    +		template 
    +		logger& operator<<(T const& v)
    +		{
    +			m_file << v;
    +			m_file.flush();
    +			return *this;
     		}
    -		virtual void log(const char* text) { assert(text); m_file << text; m_file.flush(); }
     
     		boost::filesystem::ofstream m_file;
     	};
    diff --git a/include/libtorrent/identify_client.hpp b/include/libtorrent/identify_client.hpp
    index 4a676ae4b..7f313ee8f 100755
    --- a/include/libtorrent/identify_client.hpp
    +++ b/include/libtorrent/identify_client.hpp
    @@ -34,12 +34,14 @@ POSSIBILITY OF SUCH DAMAGE.
     #define TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED
     
     #include "libtorrent/peer_id.hpp"
    +#include "libtorrent/fingerprint.hpp"
     #include "libtorrent/config.hpp"
     
     namespace libtorrent
     {
     
     	TORRENT_EXPORT std::string identify_client(const peer_id& p);
    +	TORRENT_EXPORT boost::optional client_fingerprint(peer_id const& p);
     
     }
     
    diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp
    index 8275a692b..e2df10238 100755
    --- a/include/libtorrent/peer_connection.hpp
    +++ b/include/libtorrent/peer_connection.hpp
    @@ -261,6 +261,7 @@ namespace libtorrent
     		// adds a block to the request queue
     		void add_request(piece_block const& b);
     		void cancel_request(piece_block const& b);
    +		void send_block_requests();
     
     		// how much bandwidth we're using, how much we want,
     		// and how much we are allowed to use.
    @@ -360,10 +361,16 @@ namespace libtorrent
     		void on_receive_data(asio::error const& error
     			, std::size_t bytes_transferred);
     
    +		// this is the limit on the number of outstanding requests
    +		// we have to this peer. This is initialized to the settings
    +		// in the session_settings structure. But it may be lowered
    +		// if the peer is known to require a smaller limit (like BitComet).
    +		// or if the extended handshake sets a limit.
    +		int m_max_out_request_queue;
    +
     	private:
     
     		void fill_send_buffer();
    -		void send_block_requests();
     
     		// the timeout in seconds
     		int m_timeout;
    @@ -386,7 +393,6 @@ namespace libtorrent
     		// buffer, the other is used to write data to
     		// be queued up.
     		std::vector m_send_buffer[2];
    -//		buffer m_send_buffer[2];
     		// the current send buffer is the one to write to.
     		// (m_current_send_buffer + 1) % 2 is the
     		// buffer we're currently waiting for.
    @@ -394,7 +400,7 @@ namespace libtorrent
     		
     		// if the sending buffer doesn't finish in one send
     		// operation, this is the position within that buffer
    -		// wher the next operation should continue
    +		// where the next operation should continue
     		int m_write_pos;
     
     		// timeouts
    diff --git a/include/libtorrent/peer_id.hpp b/include/libtorrent/peer_id.hpp
    index ad72a15c2..3cdfcdc83 100755
    --- a/include/libtorrent/peer_id.hpp
    +++ b/include/libtorrent/peer_id.hpp
    @@ -51,6 +51,7 @@ namespace libtorrent
     		// the number of bytes of the number
     		enum { number_size = 20 };
     	public:
    +		enum { size = number_size };
     
     		big_number() {}
     
    diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp
    index 126e7e895..a6cd0f00f 100755
    --- a/include/libtorrent/policy.hpp
    +++ b/include/libtorrent/policy.hpp
    @@ -62,7 +62,6 @@ namespace libtorrent
     	enum
     	{
     		// the limits of the download queue size
    -		max_request_queue = 48,
     		min_request_queue = 2,
     
     		// the amount of free upload allowed before
    diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp
    index 926faf6a9..80a5d5320 100644
    --- a/include/libtorrent/session_settings.hpp
    +++ b/include/libtorrent/session_settings.hpp
    @@ -42,8 +42,10 @@ namespace libtorrent
     			: piece_timeout(120)
     			, request_queue_time(3.f)
     			, sequenced_download_threshold(7)
    -			, max_allowed_request_queue(200)
    -			{}
    +			, max_allowed_in_request_queue(250)
    +			, max_out_request_queue(200)
    +			, whole_pieces_threshold(20)
    +		{}
     
     		// the number of seconds from a request is sent until
     		// it times out if no piece response is returned.
    @@ -70,7 +72,20 @@ namespace libtorrent
     		// been sent) the last request will be dropped.
     		// the higher this is, the faster upload speeds the
     		// client can get to a single peer.
    -		int max_allowed_request_queue;
    +		int max_allowed_in_request_queue;
    +		
    +		// the maximum number of outstanding requests to
    +		// send to a peer. This limit takes precedence over
    +		// request_queue_time.
    +		int max_out_request_queue;
    +		
    +		// if a whole piece can be downloaded in this number
    +		// of seconds, or less, the peer_connection will prefer
    +		// to request whole pieces at a time from this peer.
    +		// The benefit of this is to better utilize disk caches by
    +		// doing localized accesses and also to make it easier
    +		// to identify bad peers if a piece fails the hash check.
    +		int whole_pieces_threshold;
     	};
     }
     
    diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
    index 68404a5c3..c72f9b5fd 100755
    --- a/include/libtorrent/torrent.hpp
    +++ b/include/libtorrent/torrent.hpp
    @@ -133,6 +133,8 @@ namespace libtorrent
     		// by the checker thread.
     		bool is_allocating() const;
     		
    +		session_settings const& settings() const;
    +		
     		// is called every second by session. This will
     		// caclulate the upload/download and number
     		// of connections this torrent needs. And prepare
    diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp
    index 06610c7a3..4b4cc2a31 100755
    --- a/src/bt_peer_connection.cpp
    +++ b/src/bt_peer_connection.cpp
    @@ -724,6 +724,14 @@ namespace libtorrent
     			if (client_info->type() == entry::string_t)
     				m_client_version = client_info->string();
     		}
    +
    +		if (entry* reqq = root.find_key("reqq"))
    +		{
    +			if (reqq->type() == entry::int_t)
    +				m_max_out_request_queue = reqq->integer();
    +			if (m_max_out_request_queue < 1)
    +				m_max_out_request_queue = 1;
    +		}
     	}
     	catch (std::exception& exc)
     	{
    @@ -1113,6 +1121,7 @@ namespace libtorrent
     		handshake["m"] = extension_list;
     		handshake["p"] = m_ses.m_listen_interface.port();
     		handshake["v"] = m_ses.m_http_settings.user_agent;
    +		handshake["reqq"] = m_ses.m_settings.max_allowed_in_request_queue;
     
     		std::vector msg;
     		bencode(std::back_inserter(msg), handshake);
    @@ -1395,12 +1404,18 @@ namespace libtorrent
     			set_pid(pid);
     			
     			m_client_version = identify_client(pid);
    +			boost::optional f = client_fingerprint(pid);
    +			if (f && std::equal(f->name, f->name + 2, "BC"))
    +			{
    +				// if this is a bitcomet client, lower the request queue size limit
    +				if (m_max_out_request_queue > 50) m_max_out_request_queue = 50;
    +			}
     
     			// disconnect if the peer has the same peer-id as ourself
     			// since it most likely is ourself then
     			if (pid == m_ses.get_peer_id())
     				throw std::runtime_error("closing connection to ourself");
    -					
    +
     			if (m_supports_extensions) write_extensions();
     /*
     			if (!m_active)
    diff --git a/src/file_win.cpp b/src/file_win.cpp
    index 3900b9949..833c2124a 100644
    --- a/src/file_win.cpp
    +++ b/src/file_win.cpp
    @@ -247,6 +247,7 @@ namespace libtorrent
     			{
     				throw_exception("file::seek");
     			}
    +			return offs.QuadPart;
     		}
     		
     		size_type tell()
    @@ -264,8 +265,8 @@ namespace libtorrent
     				throw_exception("file::tell");
     			}
     
    -			size_type pos=offs.QuadPart;
    -			assert(pos>=0);
    +			size_type pos = offs.QuadPart;
    +			assert(pos >= 0);
     			return pos;
     		}
     /*
    diff --git a/src/identify_client.cpp b/src/identify_client.cpp
    index f14ef672f..3765329f2 100755
    --- a/src/identify_client.cpp
    +++ b/src/identify_client.cpp
    @@ -226,7 +226,24 @@ namespace
     namespace libtorrent
     {
     
    -	std::string identify_client(const peer_id& p)
    +	boost::optional client_fingerprint(peer_id const& p)
    +	{
    +		// look for azureus style id
    +		boost::optional f;
    +		f = parse_az_style(p);
    +		if (f) return f;
    +
    +		// look for shadow style id
    +		f = parse_shadow_style(p);
    +		if (f) return f;
    +
    +		// look for mainline style id
    +		f = parse_mainline_style(p);
    +		if (f) return f;
    +		return f;
    +	}
    +
    +	std::string identify_client(peer_id const& p)
     	{
     		peer_id::const_iterator PID = p.begin();
     		boost::optional f;
    diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
    index ae43e86fc..eb5b39dba 100755
    --- a/src/peer_connection.cpp
    +++ b/src/peer_connection.cpp
    @@ -82,6 +82,7 @@ namespace libtorrent
     		,
     #endif
     		  m_ses(ses)
    +		, m_max_out_request_queue(m_ses.m_settings.max_out_request_queue)
     		, m_timeout(120)
     		, m_last_piece(second_clock::universal_time())
     		, m_packet_size(0)
    @@ -172,6 +173,7 @@ namespace libtorrent
     		,
     #endif
     		  m_ses(ses)
    +		, m_max_out_request_queue(m_ses.m_settings.max_out_request_queue)
     		, m_timeout(120)
     		, m_last_piece(second_clock::universal_time())
     		, m_packet_size(0)
    @@ -792,7 +794,7 @@ namespace libtorrent
     			return;
     		}
     
    -		if (int(m_requests.size()) > m_ses.m_settings.max_allowed_request_queue)
    +		if (int(m_requests.size()) > m_ses.m_settings.max_allowed_in_request_queue)
     		{
     			// don't allow clients to abuse our
     			// memory consumption.
    @@ -830,7 +832,7 @@ namespace libtorrent
     				return;
     
     			m_requests.push_back(r);
    -			setup_send();
    +			fill_send_buffer();
     #ifdef TORRENT_VERBOSE_LOGGING
     			using namespace boost::posix_time;
     			(*m_logger) << to_simple_string(second_clock::universal_time())
    @@ -1093,7 +1095,6 @@ namespace libtorrent
     
     		t->picker().mark_as_downloading(block, m_remote);
     		m_request_queue.push_back(block);
    -		send_block_requests();
     	}
     
     	void peer_connection::cancel_request(piece_block const& block)
    @@ -1410,10 +1411,10 @@ namespace libtorrent
     		
     		m_desired_queue_size = static_cast(queue_time
     			* statistics().download_rate() / block_size);
    -		if (m_desired_queue_size > max_request_queue) m_desired_queue_size
    -			= max_request_queue;
    -		if (m_desired_queue_size < min_request_queue) m_desired_queue_size
    -			= min_request_queue;
    +		if (m_desired_queue_size > m_max_out_request_queue)
    +			m_desired_queue_size = m_max_out_request_queue;
    +		if (m_desired_queue_size < min_request_queue)
    +			m_desired_queue_size = min_request_queue;
     
     		if (!m_download_queue.empty()
     			&& now - m_last_piece > seconds(m_ses.m_settings.piece_timeout))
    @@ -1550,8 +1551,6 @@ namespace libtorrent
     	{
     		INVARIANT_CHECK;
     
    -		if (!can_write()) return;
    -
     		boost::shared_ptr t = m_torrent.lock();
     		if (!t) return;
     
    @@ -1778,8 +1777,7 @@ namespace libtorrent
     
     		// if we have requests or pending data to be sent or announcements to be made
     		// we want to send data
    -		return ((!m_requests.empty() && !m_choked)
    -			|| !m_send_buffer[m_current_send_buffer].empty()
    +		return (!m_send_buffer[m_current_send_buffer].empty()
     			|| !m_send_buffer[(m_current_send_buffer + 1) & 1].empty())
     			&& m_ul_bandwidth_quota.left() > 0
     			&& !m_connecting;
    diff --git a/src/policy.cpp b/src/policy.cpp
    index 8cb1fbe57..5afc60aec 100755
    --- a/src/policy.cpp
    +++ b/src/policy.cpp
    @@ -94,7 +94,8 @@ namespace
     		// for this peer. If we're downloading one piece in 20 seconds
     		// then use this mode.
     		// TODO: 20 seconds has to be customizable
    -		bool prefer_whole_pieces = c.statistics().download_payload_rate() * 20.f
    +		bool prefer_whole_pieces = c.statistics().download_payload_rate()
    +			* t.settings().whole_pieces_threshold
     			> t.torrent_file().piece_length();
     	
     		// if we prefer whole pieces, the piece picker will pick at least
    @@ -131,6 +132,8 @@ namespace
     			num_requests--;
     		}
     
    +		c.send_block_requests();
    +
     		// in this case, we could not find any blocks
     		// that was free. If we couldn't find any busy
     		// blocks as well, we cannot download anything
    @@ -222,6 +225,7 @@ namespace
     
     			if (weight <= min_weight) break;
     		}
    +		c.send_block_requests();
     	}
     
     
    diff --git a/src/session.cpp b/src/session.cpp
    index c9aeea9bf..e2493dabc 100755
    --- a/src/session.cpp
    +++ b/src/session.cpp
    @@ -372,6 +372,7 @@ namespace libtorrent { namespace detail
     		for (std::deque >::iterator i
     			= m_processing.begin(); i != m_processing.end(); ++i)
     		{
    +			
     			if ((*i)->info_hash == info_hash) return i->get();
     		}
     
    @@ -390,6 +391,17 @@ namespace libtorrent { namespace detail
     				return;
     			}
     		}
    +		for (std::deque >::iterator i
    +			= m_processing.begin(); i != m_processing.end(); ++i)
    +		{
    +			if ((*i)->info_hash == info_hash)
    +			{
    +				assert((*i)->processing == false);
    +				m_torrents.erase(i);
    +				return;
    +			}
    +		}
    +
     		assert(false);
     	}
     
    @@ -839,6 +851,9 @@ namespace libtorrent { namespace detail
     		for (std::map >::iterator i
     				= m_torrents.begin(); i != m_torrents.end(); ++i)
     		{
    +#ifndef DEBUG
    +			i->second->check_invariant();
    +#endif
     			i->second->distribute_resources();
     		}
     	}
    @@ -955,7 +970,7 @@ namespace libtorrent { namespace detail
     	boost::shared_ptr session_impl::create_log(std::string const& name, bool append)
     	{
     		// current options are file_logger, cout_logger and null_logger
    -		return boost::shared_ptr(new file_logger(name + ".log", append));
    +		return boost::shared_ptr(new logger(name + ".log", append));
     	}
     #endif
     
    diff --git a/src/torrent.cpp b/src/torrent.cpp
    index 177d97215..d305fcc7e 100755
    --- a/src/torrent.cpp
    +++ b/src/torrent.cpp
    @@ -1322,7 +1322,10 @@ namespace libtorrent
     		return torrent_handle(&m_ses, 0, m_torrent_file.info_hash());
     	}
     
    -
    +	session_settings const& torrent::settings() const
    +	{
    +		return m_ses.m_settings;
    +	}
     
     #ifndef NDEBUG
     	void torrent::check_invariant() const
    @@ -1599,6 +1602,7 @@ namespace libtorrent
     		{
     			bencode(std::back_inserter(m_metadata)
     				, m_torrent_file.create_info_metadata());
    +
     			assert(hasher(&m_metadata[0], m_metadata.size()).final()
     				== m_torrent_file.info_hash());
     		}