diff --git a/docs/manual.html b/docs/manual.html index 9e964b499..fe43227d5 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -1002,8 +1002,17 @@ entry write_resume_data();

write_resume_data() generates fast-resume data and returns it as an entry. This entry -is suitable for being bencoded. For more information about how fast-resume works, see fast resume. -It may throw invalid_handle if the torrent handle is invalid.

+is suitable for being bencoded. For more information about how fast-resume works, see fast resume.

+

There are three cases where this function will just return an empty entry:

+
+
    +
  1. The torrent handle is invalid.
  2. +
  3. The torrent is checking (or is queued for checking) its storage, it will obviously +not be ready to write resume data.
  4. +
  5. The torrent hasn't received valid metadata and was started without metadata +(see libtorrent's metadata from peers extension)
  6. +
+

Note that by the time this function returns, the resume data may already be invalid if the torrent is still downloading! The recommended practice is to first pause the torrent, then generate the fast resume data, and then close it down.

@@ -1820,7 +1829,7 @@ struct torrent_finished_alert: alert

metadata_received_alert

This alert is generated when the metadata has been completely received and the torrent -can start downloading. It is not generated on torrents that are started with metadata, bu +can start downloading. It is not generated on torrents that are started with metadata, but only those that needs to download it from peers (when utilizing the libtorrent extension). It is generated at severity level info.

@@ -2130,7 +2139,7 @@ piece.
 
 adler32
 The adler32 checksum of the data in the
-blocks specified by bitmsk.
+blocks specified by bitmask.
 
 
 
diff --git a/docs/manual.rst b/docs/manual.rst
index 7bdf66ba8..0dc4af2b2 100755
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -957,7 +957,14 @@ write_resume_data()
 
 ``write_resume_data()`` generates fast-resume data and returns it as an entry_. This entry_
 is suitable for being bencoded. For more information about how fast-resume works, see `fast resume`_.
-It may throw invalid_handle_ if the torrent handle is invalid.
+
+There are three cases where this function will just return an empty ``entry``:
+
+	1. The torrent handle is invalid.
+	2. The torrent is checking (or is queued for checking) its storage, it will obviously
+	   not be ready to write resume data.
+	3. The torrent hasn't received valid metadata and was started without metadata
+	   (see libtorrent's `metadata from peers`_ extension)
 
 Note that by the time this function returns, the resume data may already be invalid if the torrent
 is still downloading! The recommended practice is to first pause the torrent, then generate the
@@ -1854,7 +1861,7 @@ metadata_received_alert
 -----------------------
 
 This alert is generated when the metadata has been completely received and the torrent
-can start downloading. It is not generated on torrents that are started with metadata, bu
+can start downloading. It is not generated on torrents that are started with metadata, but
 only those that needs to download it from peers (when utilizing the libtorrent extension).
 It is generated at severity level ``info``.
 
@@ -2174,7 +2181,7 @@ The file format is a bencoded dictionary containing the following fields:
 |                      | |             | piece.                                     | |
 |                      | +-------------+--------------------------------------------+ |
 |                      | | ``adler32`` | The adler32 checksum of the data in the    | |
-|                      | |             | blocks specified by ``bitmsk``.            | |
+|                      | |             | blocks specified by ``bitmask``.           | |
 |                      | |             |                                            | |
 |                      | +-------------+--------------------------------------------+ |
 |                      |                                                              |
diff --git a/include/libtorrent/hasher.hpp b/include/libtorrent/hasher.hpp
index de34c41b3..0de45b770 100755
--- a/include/libtorrent/hasher.hpp
+++ b/include/libtorrent/hasher.hpp
@@ -84,11 +84,18 @@ namespace libtorrent
 	public:
 
 		hasher() { SHA1Init(&m_context); }
+		hasher(const char* data, int len)
+		{
+			SHA1Init(&m_context);
+			assert(data != 0);
+			assert(len > 0);
+			SHA1Update(&m_context, reinterpret_cast(data), len);
+		}
 		void update(const char* data, int len)
 		{
 			assert(data != 0);
 			assert(len > 0);
-			SHA1Update(&m_context, reinterpret_cast(const_cast(data)), len);
+			SHA1Update(&m_context, reinterpret_cast(data), len);
 		}
 
 		sha1_hash final()
diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp
index b42c61891..43c183b0b 100755
--- a/include/libtorrent/http_tracker_connection.hpp
+++ b/include/libtorrent/http_tracker_connection.hpp
@@ -71,7 +71,7 @@ namespace libtorrent
 			, std::string const& hostname
 			, unsigned short port
 			, std::string const& request
-			, request_callback* c
+			, boost::weak_ptr c
 			, const http_settings& stn
 			, std::string const& password = "");
 		virtual bool tick();
diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp
index ebf179449..ac1999339 100755
--- a/include/libtorrent/piece_picker.hpp
+++ b/include/libtorrent/piece_picker.hpp
@@ -65,10 +65,18 @@ namespace libtorrent
 		{}
 		int piece_index;
 		int block_index;
-		bool operator==(const piece_block& b) const
+
+		bool operator<(piece_block const& b) const
+		{
+			if (piece_index < b.piece_index) return true;
+			if (piece_index == b.piece_index) return block_index < b.block_index;
+			return false;
+		}
+
+		bool operator==(piece_block const& b) const
 		{ return piece_index == b.piece_index && block_index == b.block_index; }
 
-		bool operator!=(const piece_block& b) const
+		bool operator!=(piece_block const& b) const
 		{ return piece_index != b.piece_index || block_index != b.block_index; }
 
 	};
diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp
index 983c31ec7..e45839490 100755
--- a/include/libtorrent/policy.hpp
+++ b/include/libtorrent/policy.hpp
@@ -202,7 +202,7 @@ namespace libtorrent
 				ptime not_tried_yet(boost::gregorian::date(1970,boost::gregorian::Jan,1));
 
 				return p.connection == 0
-					&& p.connected!=not_tried_yet
+					&& p.connected != not_tried_yet
 					&& second_clock::local_time() - p.connected > minutes(30);
 			}
 		};
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index 99dce9372..ee6caeded 100755
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -115,7 +115,10 @@ namespace libtorrent
 		// loop in session_impl will check for this state
 		// on all torrents once every second, and take
 		// the necessary actions then.
-		void abort() { m_abort = true; m_event = tracker_request::stopped; }
+		void abort()
+		{
+			m_abort = true; m_event = tracker_request::stopped;
+		}
 		bool is_aborted() const { return m_abort; }
 
 		// is called every second by session. This will
diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp
index 309dcba04..3d96551e9 100755
--- a/include/libtorrent/tracker_manager.hpp
+++ b/include/libtorrent/tracker_manager.hpp
@@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include 
 #include 
 #include 
+#include 
 
 #ifdef _MSC_VER
 #pragma warning(pop)
@@ -98,7 +99,7 @@ namespace libtorrent
 	{
 		friend class tracker_manager;
 		request_callback(): m_manager(0) {}
-		virtual ~request_callback();
+		virtual ~request_callback() {}
 		virtual void tracker_response(
 			std::vector& peers
 			, int interval) = 0;
@@ -118,18 +119,19 @@ namespace libtorrent
 
 	struct tracker_connection: boost::noncopyable
 	{
-		tracker_connection(request_callback* r)
+		tracker_connection(boost::weak_ptr r)
 			: m_requester(r)
 		{}
 
 		virtual bool tick() = 0;
 		virtual bool send_finished() const = 0;
-		request_callback* requester() { return m_requester; }
+		bool has_requester() const { return !m_requester.expired(); }
+		request_callback& requester();
 		virtual ~tracker_connection() {}
 
-	private:
+	protected:
 
-		request_callback* m_requester;
+		boost::weak_ptr m_requester;
 
 	};
 
@@ -143,9 +145,10 @@ namespace libtorrent
 		void tick();
 		void queue_request(
 			tracker_request r
-			, request_callback* c = 0
+			, boost::weak_ptr c
+				= boost::weak_ptr()
 			, std::string const& password = "");
-		void abort_request(request_callback* c);
+//		void abort_request(request_callback* c);
 		void abort_all_requests();
 		bool send_finished() const;
 
@@ -156,10 +159,10 @@ namespace libtorrent
 		tracker_connections_t m_connections;
 		const http_settings& m_settings;
 	};
-
+/*
 	inline request_callback::~request_callback()
 	{ if (m_manager) m_manager->abort_request(this); }
-
+*/
 }
 
 #endif // TORRENT_TRACKER_MANAGER_HPP_INCLUDED
diff --git a/include/libtorrent/udp_tracker_connection.hpp b/include/libtorrent/udp_tracker_connection.hpp
index cce11a0da..da980229b 100755
--- a/include/libtorrent/udp_tracker_connection.hpp
+++ b/include/libtorrent/udp_tracker_connection.hpp
@@ -68,7 +68,7 @@ namespace libtorrent
 			tracker_request const& req
 			, std::string const& hostname
 			, unsigned short port
-			, request_callback* c
+			, boost::weak_ptr c
 			, const http_settings& stn);
 
 		virtual bool tick();
diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp
index 419fceb16..8a98f4830 100755
--- a/src/http_tracker_connection.cpp
+++ b/src/http_tracker_connection.cpp
@@ -81,7 +81,7 @@ namespace libtorrent
 		, std::string const& hostname
 		, unsigned short port
 		, std::string const& request
-		, request_callback* c
+		, boost::weak_ptr c
 		, const http_settings& stn
 		, std::string const& password)
 		: tracker_connection(c)
@@ -114,7 +114,7 @@ namespace libtorrent
 		// TODO: this is a problem. DNS-lookup is blocking!
 		// (may block up to 5 seconds)
 		address a(connect_to_host->c_str(), port);
-		if (c) c->m_tracker_address = a;
+		if (has_requester()) requester().m_tracker_address = a;
 		boost::shared_ptr s(new socket(socket::tcp, false));
 		s->connect(a);
 
@@ -191,12 +191,12 @@ namespace libtorrent
 		}
 		m_send_buffer += "\r\n\r\n";
 	#ifndef NDEBUG
-		if (c)
+		if (has_requester())
 		{
-			c->debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]");
+			requester().debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]");
 			std::stringstream info_hash_str;
 			info_hash_str << req.info_hash;
-			c->debug_log("info_hash: " + info_hash_str.str() + "\n");
+			requester().debug_log("info_hash: " + info_hash_str.str() + "\n");
 		}
 	#endif
 		m_socket = s;
@@ -215,14 +215,14 @@ namespace libtorrent
 
 		time_duration d = second_clock::local_time() - m_request_time;
 		if (d > seconds(m_settings.tracker_timeout) ||
-			(requester() == 0 && d > seconds(m_settings.stop_tracker_timeout)))
+			(!has_requester() && d > seconds(m_settings.stop_tracker_timeout)))
 		{
-			if (requester()) requester()->tracker_request_timed_out();
+			if (has_requester()) requester().tracker_request_timed_out();
 			return true;
 		}
 
 	#ifndef NDEBUG
-		if (requester()) requester()->debug_log("tracker connection tick");
+		if (has_requester()) requester().debug_log("tracker connection tick");
 	#endif
 
 		// if we have a send buffer and the socket is ready for writing
@@ -257,7 +257,7 @@ namespace libtorrent
 		m_request_time = boost::posix_time::second_clock::local_time();
 
 	#ifndef NDEBUG
-		if (requester()) requester()->debug_log("tracker connection socket readable");
+		if (has_requester()) requester().debug_log("tracker connection socket readable");
 	#endif
 
 		// if the receive buffer is full, expand it with http_buffer_size
@@ -265,9 +265,9 @@ namespace libtorrent
 		{
 			if ((int)m_buffer.size() > m_settings.tracker_maximum_response_length)
 			{
-				if (requester())
+				if (has_requester())
 				{
-					requester()->tracker_request_error(
+					requester().tracker_request_error(
 						200
 						, "too large tracker response");
 				}
@@ -287,16 +287,16 @@ namespace libtorrent
 		if (received > 0) m_recv_pos += received;
 
 	#ifndef NDEBUG
-		if (requester()) requester()->debug_log("received: " + boost::lexical_cast(m_recv_pos));
+		if (has_requester()) requester().debug_log("received: " + boost::lexical_cast(m_recv_pos));
 	#endif
 
 		if (m_state == read_status)
 		{
 			if (received <= 0)
 			{
-				if (requester())
+				if (has_requester())
 				{
-					requester()->tracker_request_error(
+					requester().tracker_request_error(
 						-1
 						, "invalid tracker response, connection closed");
 				}
@@ -309,7 +309,7 @@ namespace libtorrent
 			if (newline == end) return false;
 
 	#ifndef NDEBUG
-			if (requester()) requester()->debug_log(std::string(m_buffer.begin(), newline));
+			if (has_requester()) requester().debug_log(std::string(m_buffer.begin(), newline));
 	#endif
 
 			std::istringstream line(std::string(m_buffer.begin(), newline));
@@ -322,7 +322,7 @@ namespace libtorrent
 			if (m_server_protocol.substr(0, 5) != "HTTP/")
 			{
 				std::string error_msg = "unknown protocol in response: " + m_server_protocol;
-				if (requester()) requester()->tracker_request_error(-1, error_msg.c_str());
+				if (has_requester()) requester().tracker_request_error(-1, error_msg.c_str());
 				return true;
 			}
 			line >> m_code;
@@ -337,7 +337,7 @@ namespace libtorrent
 			{
 				std::string error_msg = boost::lexical_cast(m_code)
 					+ " " + m_server_message;
-				if (requester()) requester()->tracker_request_error(
+				if (has_requester()) requester().tracker_request_error(
 					m_code, error_msg.c_str());
 				return true;
 			}
@@ -347,8 +347,8 @@ namespace libtorrent
 		{
 			if (received <= 0)
 			{
-				if (requester())
-					requester()->tracker_request_error(-1, "invalid tracker "
+				if (has_requester())
+					requester().tracker_request_error(-1, "invalid tracker "
 					"response, connection closed while reading header");
 				return true;
 			}
@@ -363,7 +363,7 @@ namespace libtorrent
 				line.assign(m_buffer.begin(), newline);
 
 	#ifndef NDEBUG
-				if (requester()) requester()->debug_log(line);
+				if (has_requester()) requester().debug_log(line);
 	#endif
 
 				if (line.substr(0, 16) == "Content-Length: ")
@@ -375,9 +375,9 @@ namespace libtorrent
 					}
 					catch(boost::bad_lexical_cast&)
 					{
-						if (requester())
+						if (has_requester())
 						{
-							requester()->tracker_request_error(
+							requester().tracker_request_error(
 								-1, 
 								"invalid content-length in tracker response");
 						}
@@ -385,9 +385,9 @@ namespace libtorrent
 					}
 					if (m_content_length > m_settings.tracker_maximum_response_length)
 					{
-						if (requester())
+						if (has_requester())
 						{
-							requester()->tracker_request_error(
+							requester().tracker_request_error(
 								-1
 								, "content-length is greater than maximum response length");
 						}
@@ -396,9 +396,9 @@ namespace libtorrent
 
 					if (m_content_length < minimum_tracker_response_length && m_code == 200)
 					{
-						if (requester())
+						if (has_requester())
 						{
-							requester()->tracker_request_error(
+							requester().tracker_request_error(
 								-1
 								, "content-length is smaller than minimum response length");
 						}
@@ -416,8 +416,8 @@ namespace libtorrent
 						std::string error_str = "unknown content encoding in response: \"";
 						error_str += line.substr(18, line.length() - 18 - 2);
 						error_str += "\"";
-						if (requester())
-							requester()->tracker_request_error(-1, error_str.c_str());
+						if (has_requester())
+							requester().tracker_request_error(-1, error_str.c_str());
 						return true;
 					}
 				}
@@ -433,7 +433,7 @@ namespace libtorrent
 				{
 					m_state = read_body;
 	#ifndef NDEBUG
-					if (requester()) requester()->debug_log("end of http header");
+					if (has_requester()) requester().debug_log("end of http header");
 	#endif
 					if (m_code >= 300 && m_code < 400)
 					{
@@ -442,13 +442,13 @@ namespace libtorrent
 							std::string error_str = "got redirection response (";
 							error_str += boost::lexical_cast(m_code);
 							error_str += ") without 'Location' header";
-							if (requester())
-								requester()->tracker_request_error(m_code, error_str.c_str());
+							if (has_requester())
+								requester().tracker_request_error(m_code, error_str.c_str());
 							return true;
 						}
 
 #ifndef NDEBUG
-						if (requester()) requester()->debug_log("Redirecting to \"" + m_location + "\"");
+						if (has_requester()) requester().debug_log("Redirecting to \"" + m_location + "\"");
 #endif
 						std::string::size_type i = m_location.find('?');
 						if (i == std::string::npos)
@@ -456,7 +456,7 @@ namespace libtorrent
 						else
 							m_req.url.assign(m_location.begin(), m_location.begin() + i);
 
-						m_man.queue_request(m_req, requester(), m_password);
+						m_man.queue_request(m_req, m_requester, m_password);
 						return true;
 					}
 				}
@@ -479,8 +479,9 @@ namespace libtorrent
 				// GZIP
 				if (m_content_encoding == gzip)
 				{
-					if (inflate_gzip(m_buffer,
-						requester(),
+					boost::shared_ptr r = m_requester.lock();
+					if (!r) return true;
+					if (inflate_gzip(m_buffer, r.get(),
 						m_settings.tracker_maximum_response_length))
 						return true;
 				}
@@ -494,9 +495,9 @@ namespace libtorrent
 		}
 		else if (m_recv_pos > m_content_length && m_content_length > 0)
 		{
-			if (requester())
+			if (has_requester())
 			{
-				requester()->tracker_request_error(
+				requester().tracker_request_error(
 					-1
 					, "invalid tracker response (body > content_length)");
 			}
@@ -508,8 +509,8 @@ namespace libtorrent
 		}
 		catch (std::exception&)
 		{
-			if (requester())
-				requester()->debug_log(std::string(m_buffer.begin(), m_buffer.end()));
+			if (has_requester())
+				requester().debug_log(std::string(m_buffer.begin(), m_buffer.end()));
 			throw;			
 		}
 #endif
@@ -548,7 +549,7 @@ namespace libtorrent
 
 	void http_tracker_connection::parse(const entry& e)
 	{
-		if (requester() == 0) return;
+		if (!has_requester()) return;
 
 		std::vector peer_list;
 		try
@@ -596,15 +597,15 @@ namespace libtorrent
 				}
 			}
 
-			requester()->tracker_response(peer_list, interval);
+			requester().tracker_response(peer_list, interval);
 		}
 		catch(type_error& e)
 		{
-			requester()->tracker_request_error(-1, e.what());
+			requester().tracker_request_error(-1, e.what());
 		}
 		catch(std::runtime_error& e)
 		{
-			requester()->tracker_request_error(-1, e.what());
+			requester().tracker_request_error(-1, e.what());
 		}
 	}
 
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index 83719b154..30260ba96 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -1951,10 +1951,6 @@ namespace libtorrent
 					// ok, now we have got enough of the handshake. Is this connection
 					// attached to a torrent?
 
-					// TODO: if the protocol is to be extended
-					// these 8 bytes would be used to describe the
-					// extensions available on the other side
-					// currently disabled
 #ifndef TORRENT_DISABLE_EXTENSIONS
 					if (m_recv_buffer[7] & 0x01)
 						m_supports_extensions = true;
diff --git a/src/policy.cpp b/src/policy.cpp
index bc04cdc5e..8105e625d 100755
--- a/src/policy.cpp
+++ b/src/policy.cpp
@@ -567,6 +567,7 @@ namespace libtorrent
 		// TODO: we must also remove peers that
 		// we failed to connect to from this list
 		// to avoid being part of a DDOS-attack
+
 		// remove old disconnected peers from the list
 		m_peers.erase(
 			std::remove_if(m_peers.begin()
@@ -770,6 +771,7 @@ namespace libtorrent
 		// if the connection comes from the tracker,
 		// it's probably just a NAT-check. Ignore the
 		// num connections constraint then.
+
 		// TODO: only allow _one_ connection to use this
 		// override at a time
 		if (m_torrent->num_peers() >= m_max_connections
@@ -928,6 +930,7 @@ namespace libtorrent
 				}
 				if (!interested)
 					i->connection->send_not_interested();
+				assert(i->connection->is_interesting() == interested);
 			}
 		}
 	}
@@ -1002,7 +1005,7 @@ namespace libtorrent
 		if (p == 0) return false;
 		assert(!p->banned);
 		assert(!p->connection);
-		assert(p->type==peer::connectable);
+		assert(p->type == peer::connectable);
 
 		return connect_peer(p);
 	}
diff --git a/src/session.cpp b/src/session.cpp
index 295fa3a11..70a0033f6 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -369,9 +369,7 @@ namespace libtorrent { namespace detail
 			{
 				m_tracker_manager.abort_all_requests();
 				for (std::map >::iterator i =
-						m_torrents.begin();
-					i != m_torrents.end();
-					++i)
+					m_torrents.begin(); i != m_torrents.end(); ++i)
 				{
 					i->second->abort();
 					tracker_request req = i->second->generate_tracker_request();
@@ -491,12 +489,6 @@ namespace libtorrent { namespace detail
 						boost::shared_ptr c(
 							new peer_connection(*this, m_selector, s));
 
-/*						if (m_upload_rate != -1)
-						{
-							c->upload_bandwidth_quota()->given = 0;
-							c->update_send_quota_left();
-						}
-*/
 						m_connections.insert(std::make_pair(s, c));
 						m_selector.monitor_readability(s);
 						m_selector.monitor_errors(s);
@@ -669,8 +661,7 @@ namespace libtorrent { namespace detail
 					req.listen_port = m_listen_interface.port;
 					req.key = m_key;
 					m_tracker_manager.queue_request(
-						req
-						, boost::get_pointer(i->second));
+						req, i->second);
 				}
 
 				// tick() will set the used upload quota
@@ -701,6 +692,9 @@ namespace libtorrent { namespace detail
 				i->second->distribute_resources();
 			}
 
+			// TODO: there's a problem when removing torrents while
+			// they're waiting for tracker response. The requester-pointer
+			// will become invalid.
 			m_tracker_manager.tick();
 		}
 
diff --git a/src/storage.cpp b/src/storage.cpp
index 4d35337a3..309de28ab 100755
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -353,8 +353,6 @@ namespace libtorrent
 			// TODO: this assert will be hit if a file has size 0
 			assert(read_bytes > 0);
 
-//			in.read(buf + buf_pos, read_bytes);
-//			int actual_read = in.gcount();
 			size_type actual_read = in.read(buf + buf_pos, read_bytes);
 
 			if (read_bytes != actual_read)
@@ -471,15 +469,7 @@ namespace libtorrent
  				fs::path path = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path);
 
 				file_offset = 0;
-/*
-				out.close();
-				out.clear();
 
-				if (fs::exists(path))
-					out.open(path, std::ios_base::binary | std::ios_base::in);
-				else
-					out.open(path, std::ios_base::binary);
-*/
 				out.open(path, file::out);
 			}
 		}
@@ -1233,7 +1223,7 @@ namespace libtorrent
 			{
 				boost::mutex::scoped_lock lock(mutex);
 				data.progress = (float)current_slot / m_info.num_pieces();
-				if (data.abort)
+				if (data.abort || data.torrent_ptr->is_aborted())
 					return;
 			}
 		}
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 9963915b7..79277ef25 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -375,11 +375,8 @@ namespace libtorrent
 			}
 		}
 
-		// TODO: may report too much if two peers are downloading
-		// the same block
-		for (const_peer_iterator i = begin();
-			i != end();
-			++i)
+		std::map downloading_piece;
+		for (const_peer_iterator i = begin(); i != end(); ++i)
 		{
 			boost::optional p
 				= i->second->downloading_piece();
@@ -387,13 +384,28 @@ namespace libtorrent
 			{
 				if (m_have_pieces[p->piece_index])
 					continue;
-				if (m_picker->is_finished(piece_block(p->piece_index, p->block_index)))
+
+				piece_block block(p->piece_index, p->block_index);
+				if (m_picker->is_finished(block))
 					continue;
 
-				total_done += p->bytes_downloaded;
+				std::map::iterator dp
+					= downloading_piece.find(block);
+				if (dp != downloading_piece.end())
+				{
+					if (dp->second < p->bytes_downloaded)
+						dp->second = p->bytes_downloaded;
+				}
+				else
+				{
+					downloading_piece[block] = p->bytes_downloaded;
+				}
 				assert(p->bytes_downloaded <= p->full_block_bytes);
 			}
 		}
+		for (std::map::iterator i = downloading_piece.begin();
+			i != downloading_piece.end(); ++i)
+			total_done += i->second;
 		return total_done;
 	}
 
@@ -945,8 +957,19 @@ namespace libtorrent
 				st.state = torrent_status::connecting_to_tracker;
 			else
 				st.state = torrent_status::downloading_metadata;
-			// TODO: implement progress
-			st.progress = 0.f;
+
+			if (m_have_metadata.empty())
+			{
+				st.progress = 0.f;
+			}
+			else
+			{
+				st.progress = std::count(
+					m_have_metadata.begin()
+					, m_have_metadata.end()
+					, true) / 256.f;
+			}
+
 			return st;
 		}
 
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 65f9bc37f..f5eb0a815 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -365,13 +365,11 @@ namespace libtorrent
 		INVARIANT_CHECK;
 
 		std::vector piece_index;
-		if (m_ses == 0)
-			throw invalid_handle();
+		if (m_ses == 0) return entry();
 
 		boost::mutex::scoped_lock l(m_ses->m_mutex);
 		torrent* t = m_ses->find_torrent(m_info_hash);
-		if (t == 0)
-			throw invalid_handle();
+		if (t == 0) return entry();
 
 		if (!t->valid_metadata()) return entry();
 
diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp
index 5abd61947..0022fcb13 100755
--- a/src/tracker_manager.cpp
+++ b/src/tracker_manager.cpp
@@ -280,6 +280,13 @@ namespace libtorrent
 		return ret;
 	}
 
+	request_callback& tracker_connection::requester()
+	{
+		boost::shared_ptr r = m_requester.lock();
+		assert(r);
+		return *r;
+	}
+
 
 	void tracker_manager::tick()
 	{
@@ -293,17 +300,17 @@ namespace libtorrent
 			}
 			catch (const std::exception& e)
 			{
-				if (c->requester())
-					c->requester()->tracker_request_error(-1, e.what());
+				if (c->has_requester())
+					c->requester().tracker_request_error(-1, e.what());
 			}
-			if (c->requester()) c->requester()->m_manager = 0;
+			if (c->has_requester()) c->requester().m_manager = 0;
 			i = m_connections.erase(i);
 		}
 	}
 
 	void tracker_manager::queue_request(
 		tracker_request req
-		, request_callback* c
+		, boost::weak_ptr c
 		, std::string const& password)
 	{
 		assert(req.num_want >= 0);
@@ -387,14 +394,18 @@ namespace libtorrent
 
 			m_connections.push_back(con);
 
-			if (con->requester()) con->requester()->m_manager = this;
+			if (con->has_requester()) con->requester().m_manager = this;
 		}
 		catch (std::exception& e)
 		{
-			if (c) c->tracker_request_error(-1, e.what());
+			if (!c.expired())
+			{
+				boost::shared_ptr r = c.lock();
+				r->tracker_request_error(-1, e.what());
+			}
 		}
 	}
-
+/*
 	void tracker_manager::abort_request(request_callback* c)
 	{
 		assert(c != 0);
@@ -408,7 +419,7 @@ namespace libtorrent
 			}
 		}
 	}
-
+*/
 	void tracker_manager::abort_all_requests()
 	{
 		// removes all connections from m_connections
@@ -422,7 +433,7 @@ namespace libtorrent
 			i != m_connections.end();
 			++i)
 		{
-			if ((*i)->requester() == 0) keep_connections.push_back(*i);
+			if (!(*i)->has_requester()) keep_connections.push_back(*i);
 		}
 
 		std::swap(m_connections, keep_connections);
diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp
index 718df786a..07b61acfc 100755
--- a/src/udp_tracker_connection.cpp
+++ b/src/udp_tracker_connection.cpp
@@ -61,7 +61,7 @@ namespace libtorrent
 		tracker_request const& req
 		, std::string const& hostname
 		, unsigned short port
-		, request_callback* c
+		, boost::weak_ptr c
 		, const http_settings& stn)
 		: tracker_connection(c)
 		, m_request_time(boost::posix_time::second_clock::local_time())
@@ -74,7 +74,7 @@ namespace libtorrent
 		// TODO: this is a problem. DNS-lookup is blocking!
 		// (may block up to 5 seconds)
 		address a(hostname.c_str(), port);
-		if (c) c->m_tracker_address = a;
+		if (has_requester()) requester().m_tracker_address = a;
 		m_socket.reset(new socket(socket::udp, false));
 		m_socket->connect(a);
 
@@ -101,7 +101,7 @@ namespace libtorrent
 		{
 			if (m_attempts >= udp_connection_retries)
 			{
-				if (requester()) requester()->tracker_request_timed_out();
+				if (has_requester()) requester().tracker_request_timed_out();
 				return true;
 			}
 			send_udp_connect();
@@ -113,7 +113,7 @@ namespace libtorrent
 		{
 			if (m_attempts >= udp_announce_retries)
 			{
-				if (requester()) requester()->tracker_request_timed_out();
+				if (has_requester()) requester().tracker_request_timed_out();
 				return true;
 			}
 
@@ -134,8 +134,8 @@ namespace libtorrent
 		}
 		if (ret == udp_buffer_size)
 		{
-			if (requester())
-				requester()->tracker_request_error(-1, "tracker reply too big");
+			if (has_requester())
+				requester().tracker_request_error(-1, "tracker reply too big");
 			return true;
 		}
 
@@ -217,8 +217,8 @@ namespace libtorrent
 		if (len < 8)
 		{
 #ifndef NDEBUG
-			if (requester())
-				requester()->debug_log("udp_tracker_connection: "
+			if (has_requester())
+				requester().debug_log("udp_tracker_connection: "
 				"got a message with size < 8, ignoring");
 #endif
 			return false;
@@ -233,8 +233,8 @@ namespace libtorrent
 
 		if (action == error)
 		{
-			if (requester())
-				requester()->tracker_request_error(-1, std::string(buf, buf + len - 8));
+			if (has_requester())
+				requester().tracker_request_error(-1, std::string(buf, buf + len - 8));
 			return true;
 		}
 		if (action != announce) return false;
@@ -242,8 +242,8 @@ namespace libtorrent
 		if (len < 12)
 		{
 #ifndef NDEBUG
-			if (requester())
-				requester()->debug_log("udp_tracker_connection: "
+			if (has_requester())
+				requester().debug_log("udp_tracker_connection: "
 				"got a message with size < 12, ignoring");
 #endif
 			return false;
@@ -252,12 +252,12 @@ namespace libtorrent
 		int num_peers = (len - 12) / 6;
 		if ((len - 12) % 6 != 0)
 		{
-			if (requester())
-				requester()->tracker_request_error(-1, "invalid tracker response");
+			if (has_requester())
+				requester().tracker_request_error(-1, "invalid tracker response");
 			return true;
 		}
 
-		if (requester() == 0) return true;
+		if (!has_requester()) return true;
 
 		std::vector peer_list;
 		for (int i = 0; i < num_peers; ++i)
@@ -274,7 +274,7 @@ namespace libtorrent
 			peer_list.push_back(e);
 		}
 
-		requester()->tracker_response(peer_list, interval);
+		requester().tracker_response(peer_list, interval);
 		return true;
 	}
 
@@ -286,8 +286,8 @@ namespace libtorrent
 		if (len < 8)
 		{
 #ifndef NDEBUG
-			if (requester())
-				requester()->debug_log("udp_tracker_connection: "
+			if (has_requester())
+				requester().debug_log("udp_tracker_connection: "
 				"got a message with size < 8, ignoring");
 #endif
 			return false;
@@ -298,16 +298,16 @@ namespace libtorrent
 
 		if (action == error)
 		{
-			if (requester())
-				requester()->tracker_request_error(-1, std::string(ptr, buf + len));
+			if (has_requester())
+				requester().tracker_request_error(-1, std::string(ptr, buf + len));
 			return true;
 		}
 		if (action != connect) return false;
 		if (m_transaction_id != transaction)
 		{
 #ifndef NDEBUG
-			if (requester())
-				requester()->debug_log("udp_tracker_connection: "
+			if (has_requester())
+				requester().debug_log("udp_tracker_connection: "
 				"got a message with incorrect transaction id, ignoring");
 #endif
 			return false;
@@ -316,8 +316,8 @@ namespace libtorrent
 		if (len < 16)
 		{
 #ifndef NDEBUG
-			if (requester())
-				requester()->debug_log("udp_tracker_connection: "
+			if (has_requester())
+				requester().debug_log("udp_tracker_connection: "
 				"got a connection message size < 16, ignoring");
 #endif
 			return false;