1 /*
2 
3 Copyright (c) 2007-2018, Arvid Norberg
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #ifndef TORRENT_DISABLE_EXTENSIONS
34 
35 #include <functional>
36 #include <vector>
37 #include <utility>
38 #include <numeric>
39 #include <cstdio>
40 
41 #include "libtorrent/peer_connection.hpp"
42 #include "libtorrent/bt_peer_connection.hpp"
43 #include "libtorrent/peer_connection_handle.hpp"
44 #include "libtorrent/bencode.hpp"
45 #include "libtorrent/torrent.hpp"
46 #include "libtorrent/torrent_handle.hpp"
47 #include "libtorrent/extensions.hpp"
48 #include "libtorrent/extensions/ut_metadata.hpp"
49 #include "libtorrent/alert_types.hpp"
50 #include "libtorrent/random.hpp"
51 #include "libtorrent/io.hpp"
52 #include "libtorrent/performance_counters.hpp" // for counters
53 #include "libtorrent/aux_/time.hpp"
54 
55 #if TORRENT_USE_ASSERTS
56 #include "libtorrent/hasher.hpp"
57 #endif
58 
59 namespace libtorrent {namespace {
60 
61 	enum
62 	{
63 		// this is the max number of bytes we'll
64 		// queue up in the send buffer. If we exceed this,
65 		// we'll wait another second before checking
66 		// the send buffer size again. So, this may limit
67 		// the rate at which we can server metadata to
68 		// 160 kiB/s
69 		send_buffer_limit = 0x4000 * 10,
70 
71 		// this is the max number of requests we'll queue
72 		// up. If we get more requests tha this, we'll
73 		// start rejecting them, claiming we don't have
74 		// metadata. If the torrent is greater than 16 MiB,
75 		// we may hit this case (and the client requesting
76 		// doesn't throttle its requests)
77 		max_incoming_requests = 1024,
78 
79 		metadata_req = 0,
80 		metadata_piece = 1,
81 		metadata_dont_have = 2
82 	};
83 
div_round_up(int numerator,int denominator)84 	int div_round_up(int numerator, int denominator)
85 	{
86 		return (numerator + denominator - 1) / denominator;
87 	}
88 
89 	struct ut_metadata_peer_plugin;
90 
91 	struct ut_metadata_plugin final
92 		: torrent_plugin
93 	{
ut_metadata_pluginlibtorrent::__anonb051ff310111::ut_metadata_plugin94 		explicit ut_metadata_plugin(torrent& t) : m_torrent(t)
95 		{
96 			// initialize m_metadata_size
97 			if (m_torrent.valid_metadata())
98 				metadata();
99 		}
100 
on_files_checkedlibtorrent::__anonb051ff310111::ut_metadata_plugin101 		void on_files_checked() override
102 		{
103 			// TODO: 2 if we were to initialize m_metadata_size lazily instead,
104 			// we would probably be more efficient
105 			// initialize m_metadata_size
106 			metadata();
107 		}
108 
109 		std::shared_ptr<peer_plugin> new_connection(
110 			peer_connection_handle const& pc) override;
111 
get_metadata_sizelibtorrent::__anonb051ff310111::ut_metadata_plugin112 		int get_metadata_size() const
113 		{
114 			TORRENT_ASSERT(m_metadata_size > 0);
115 			return m_metadata_size;
116 		}
117 
metadatalibtorrent::__anonb051ff310111::ut_metadata_plugin118 		span<char const> metadata() const
119 		{
120 			TORRENT_ASSERT(m_torrent.valid_metadata());
121 			if (!m_metadata)
122 			{
123 				m_metadata = m_torrent.torrent_file().metadata();
124 				m_metadata_size = m_torrent.torrent_file().metadata_size();
125 				TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
126 					== m_torrent.torrent_file().info_hash());
127 			}
128 			return {m_metadata.get(), m_metadata_size};
129 		}
130 
131 		bool received_metadata(ut_metadata_peer_plugin& source
132 			, span<char const> buf, int piece, int total_size);
133 
134 		// returns a piece of the metadata that
135 		// we should request.
136 		// returns -1 if we should hold off the request
137 		int metadata_request(bool has_metadata);
138 
on_piece_passlibtorrent::__anonb051ff310111::ut_metadata_plugin139 		void on_piece_pass(piece_index_t) override
140 		{
141 			// if we became a seed, copy the metadata from
142 			// the torrent before it is deallocated
143 			if (m_torrent.is_seed())
144 				metadata();
145 		}
146 
metadata_sizelibtorrent::__anonb051ff310111::ut_metadata_plugin147 		void metadata_size(int const size)
148 		{
149 			if (m_metadata_size > 0 || size <= 0 || size > 4 * 1024 * 1024) return;
150 			m_metadata_size = size;
151 			m_metadata.reset(new char[std::size_t(size)]);
152 			m_requested_metadata.resize(div_round_up(size, 16 * 1024));
153 		}
154 
155 		// explicitly disallow assignment, to silence msvc warning
156 		ut_metadata_plugin& operator=(ut_metadata_plugin const&) = delete;
157 
158 	private:
159 		torrent& m_torrent;
160 
161 		// this buffer is filled with the info-section of
162 		// the metadata file while downloading it from
163 		// peers, and while sending it.
164 		// it is mutable because it's generated lazily
165 		mutable boost::shared_array<char> m_metadata;
166 
167 		mutable int m_metadata_size = 0;
168 
169 		struct metadata_piece
170 		{
metadata_piecelibtorrent::__anonb051ff310111::ut_metadata_plugin::metadata_piece171 			metadata_piece(): num_requests(0), last_request(min_time()) {}
172 			int num_requests;
173 			time_point last_request;
174 			std::weak_ptr<ut_metadata_peer_plugin> source;
operator <libtorrent::__anonb051ff310111::ut_metadata_plugin::metadata_piece175 			bool operator<(metadata_piece const& rhs) const
176 			{ return num_requests < rhs.num_requests; }
177 		};
178 
179 		// this vector keeps track of how many times each metadata
180 		// block has been requested and who we ended up getting it from
181 		// std::numeric_limits<int>::max() means we have the piece
182 		aux::vector<metadata_piece> m_requested_metadata;
183 	};
184 
185 
186 	struct ut_metadata_peer_plugin final
187 		: peer_plugin, std::enable_shared_from_this<ut_metadata_peer_plugin>
188 	{
189 		friend struct ut_metadata_plugin;
190 
ut_metadata_peer_pluginlibtorrent::__anonb051ff310111::ut_metadata_peer_plugin191 		ut_metadata_peer_plugin(torrent& t, bt_peer_connection& pc
192 			, ut_metadata_plugin& tp)
193 			: m_message_index(0)
194 			, m_request_limit(min_time())
195 			, m_torrent(t)
196 			, m_pc(pc)
197 			, m_tp(tp)
198 		{}
199 
200 		// can add entries to the extension handshake
add_handshakelibtorrent::__anonb051ff310111::ut_metadata_peer_plugin201 		void add_handshake(entry& h) override
202 		{
203 			entry& messages = h["m"];
204 			messages["ut_metadata"] = 2;
205 			if (m_torrent.valid_metadata())
206 				h["metadata_size"] = m_tp.get_metadata_size();
207 		}
208 
209 		// called when the extension handshake from the other end is received
on_extension_handshakelibtorrent::__anonb051ff310111::ut_metadata_peer_plugin210 		bool on_extension_handshake(bdecode_node const& h) override
211 		{
212 			m_message_index = 0;
213 			if (h.type() != bdecode_node::dict_t) return false;
214 			bdecode_node const messages = h.dict_find_dict("m");
215 			if (!messages) return false;
216 
217 			int index = int(messages.dict_find_int_value("ut_metadata", -1));
218 			if (index == -1) return false;
219 			m_message_index = index;
220 
221 			int metadata_size = int(h.dict_find_int_value("metadata_size"));
222 			if (metadata_size > 0)
223 				m_tp.metadata_size(metadata_size);
224 			else
225 				m_pc.set_has_metadata(false);
226 
227 			maybe_send_request();
228 			return true;
229 		}
230 
write_metadata_packetlibtorrent::__anonb051ff310111::ut_metadata_peer_plugin231 		void write_metadata_packet(int const type, int const piece)
232 		{
233 			TORRENT_ASSERT(type >= 0 && type <= 2);
234 			TORRENT_ASSERT(!m_pc.associated_torrent().expired());
235 
236 #ifndef TORRENT_DISABLE_LOGGING
237 			static char const* names[] = {"request", "data", "dont-have"};
238 			char const* n = "";
239 			if (type >= 0 && type < 3) n = names[type];
240 			m_pc.peer_log(peer_log_alert::outgoing_message, "UT_METADATA"
241 				, "type: %d (%s) piece: %d", type, n, piece);
242 #endif
243 
244 			// abort if the peer doesn't support the metadata extension
245 			if (m_message_index == 0) return;
246 
247 			entry e;
248 			e["msg_type"] = type;
249 			e["piece"] = piece;
250 
251 			char const* metadata = nullptr;
252 			int metadata_piece_size = 0;
253 
254 			if (m_torrent.valid_metadata())
255 				e["total_size"] = m_tp.get_metadata_size();
256 
257 			if (type == 1)
258 			{
259 				TORRENT_ASSERT(piece >= 0 && piece < (m_tp.get_metadata_size() + 16 * 1024 - 1) / (16 * 1024));
260 				TORRENT_ASSERT(m_pc.associated_torrent().lock()->valid_metadata());
261 				TORRENT_ASSERT(m_torrent.valid_metadata());
262 
263 				int const offset = piece * 16 * 1024;
264 				metadata = m_tp.metadata().data() + offset;
265 				metadata_piece_size = std::min(
266 					m_tp.get_metadata_size() - offset, 16 * 1024);
267 				TORRENT_ASSERT(metadata_piece_size > 0);
268 				TORRENT_ASSERT(offset >= 0);
269 				TORRENT_ASSERT(offset + metadata_piece_size <= m_tp.get_metadata_size());
270 			}
271 
272 			// TODO: 3 use the aux::write_* functions and the span here instead, it
273 			// will fit better with send_buffer()
274 			char msg[200];
275 			char* header = msg;
276 			char* p = &msg[6];
277 			int const len = bencode(p, e);
278 			int const total_size = 2 + len + metadata_piece_size;
279 			namespace io = detail;
280 			io::write_uint32(total_size, header);
281 			io::write_uint8(bt_peer_connection::msg_extended, header);
282 			io::write_uint8(m_message_index, header);
283 
284 			m_pc.send_buffer({msg, len + 6});
285 			// TODO: we really need to increment the refcounter on the torrent
286 			// while this buffer is still in the peer's send buffer
287 			if (metadata_piece_size)
288 			{
289 				m_pc.append_const_send_buffer(
290 					span<char>(const_cast<char*>(metadata), metadata_piece_size), metadata_piece_size);
291 			}
292 
293 			m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_extended);
294 			m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_metadata);
295 		}
296 
on_extendedlibtorrent::__anonb051ff310111::ut_metadata_peer_plugin297 		bool on_extended(int const length
298 			, int const extended_msg, span<char const> body) override
299 		{
300 			if (extended_msg != 2) return false;
301 			if (m_message_index == 0) return false;
302 
303 			if (length > 17 * 1024)
304 			{
305 #ifndef TORRENT_DISABLE_LOGGING
306 				m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"
307 					, "packet too big %d", length);
308 #endif
309 				m_pc.disconnect(errors::invalid_metadata_message, operation_t::bittorrent, peer_connection_interface::peer_error);
310 				return true;
311 			}
312 
313 			if (!m_pc.packet_finished()) return true;
314 
315 			error_code ec;
316 			bdecode_node msg = bdecode(body, ec);
317 			if (msg.type() != bdecode_node::dict_t)
318 			{
319 #ifndef TORRENT_DISABLE_LOGGING
320 				m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"
321 					, "not a dictionary");
322 #endif
323 				m_pc.disconnect(errors::invalid_metadata_message, operation_t::bittorrent, peer_connection_interface::peer_error);
324 				return true;
325 			}
326 
327 			bdecode_node const& type_ent = msg.dict_find_int("msg_type");
328 			bdecode_node const& piece_ent = msg.dict_find_int("piece");
329 			if (!type_ent || !piece_ent)
330 			{
331 #ifndef TORRENT_DISABLE_LOGGING
332 				m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"
333 					, "missing or invalid keys");
334 #endif
335 				m_pc.disconnect(errors::invalid_metadata_message, operation_t::bittorrent, peer_connection_interface::peer_error);
336 				return true;
337 			}
338 			// TODO: make this an enum class
339 			auto const type = static_cast<int>(type_ent.int_value());
340 			auto const piece = static_cast<int>(piece_ent.int_value());
341 
342 #ifndef TORRENT_DISABLE_LOGGING
343 			m_pc.peer_log(peer_log_alert::incoming_message, "UT_METADATA"
344 				, "type: %d piece: %d", type, piece);
345 #endif
346 
347 			switch (type)
348 			{
349 				case metadata_req:
350 				{
351 					if (!m_torrent.valid_metadata()
352 						|| piece < 0 || piece >= (m_tp.get_metadata_size() + 16 * 1024 - 1) / (16 * 1024))
353 					{
354 #ifndef TORRENT_DISABLE_LOGGING
355 						if (m_pc.should_log(peer_log_alert::info))
356 						{
357 							m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
358 								, "have: %d invalid piece %d metadata size: %d"
359 								, int(m_torrent.valid_metadata()), piece
360 								, m_torrent.valid_metadata()
361 									? m_tp.get_metadata_size() : 0);
362 						}
363 #endif
364 						write_metadata_packet(metadata_dont_have, piece);
365 						return true;
366 					}
367 					if (m_pc.send_buffer_size() < send_buffer_limit)
368 						write_metadata_packet(metadata_piece, piece);
369 					else if (m_incoming_requests.size() < max_incoming_requests)
370 						m_incoming_requests.push_back(piece);
371 					else
372 						write_metadata_packet(metadata_dont_have, piece);
373 				}
374 				break;
375 				case metadata_piece:
376 				{
377 					auto const i = std::find(m_sent_requests.begin()
378 						, m_sent_requests.end(), piece);
379 
380 					// unwanted piece?
381 					if (i == m_sent_requests.end())
382 					{
383 #ifndef TORRENT_DISABLE_LOGGING
384 						m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
385 							, "UNWANTED / TIMED OUT");
386 #endif
387 						return true;
388 					}
389 
390 					m_sent_requests.erase(i);
391 					auto const len = msg.data_section().size();
392 					auto const total_size = msg.dict_find_int_value("total_size", 0);
393 					m_tp.received_metadata(*this, body.subspan(len), piece, static_cast<int>(total_size));
394 					maybe_send_request();
395 				}
396 				break;
397 				case metadata_dont_have:
398 				{
399 					m_request_limit = std::max(aux::time_now() + minutes(1), m_request_limit);
400 					auto const i = std::find(m_sent_requests.begin()
401 						, m_sent_requests.end(), piece);
402 					// unwanted piece?
403 					if (i == m_sent_requests.end()) return true;
404 					m_sent_requests.erase(i);
405 				}
406 				break;
407 			default:
408 				// unknown message, ignore
409 				break;
410 			}
411 
412 			m_pc.stats_counters().inc_stats_counter(counters::num_incoming_metadata);
413 
414 			return true;
415 		}
416 
ticklibtorrent::__anonb051ff310111::ut_metadata_peer_plugin417 		void tick() override
418 		{
419 			maybe_send_request();
420 			while (!m_incoming_requests.empty()
421 				&& m_pc.send_buffer_size() < send_buffer_limit)
422 			{
423 				int const piece = m_incoming_requests.front();
424 				m_incoming_requests.erase(m_incoming_requests.begin());
425 				write_metadata_packet(metadata_piece, piece);
426 			}
427 		}
428 
maybe_send_requestlibtorrent::__anonb051ff310111::ut_metadata_peer_plugin429 		void maybe_send_request()
430 		{
431 			if (m_pc.is_disconnecting()) return;
432 
433 			// if we don't have any metadata, and this peer
434 			// supports the request metadata extension
435 			// and we aren't currently waiting for a request
436 			// reply. Then, send a request for some metadata.
437 			if (!m_torrent.valid_metadata()
438 				&& m_message_index != 0
439 				&& m_sent_requests.size() < 2
440 				&& has_metadata())
441 			{
442 				int const piece = m_tp.metadata_request(m_pc.has_metadata());
443 				if (piece == -1) return;
444 
445 				m_sent_requests.push_back(piece);
446 				write_metadata_packet(metadata_req, piece);
447 			}
448 		}
449 
has_metadatalibtorrent::__anonb051ff310111::ut_metadata_peer_plugin450 		bool has_metadata() const
451 		{
452 			return m_pc.has_metadata() || (aux::time_now() > m_request_limit);
453 		}
454 
failed_hash_checklibtorrent::__anonb051ff310111::ut_metadata_peer_plugin455 		void failed_hash_check(time_point const& now)
456 		{
457 			m_request_limit = now + seconds(20 + random(50));
458 		}
459 
460 		// explicitly disallow assignment, to silence msvc warning
461 		ut_metadata_peer_plugin& operator=(ut_metadata_peer_plugin const&) = delete;
462 
463 	private:
464 
465 		// this is the message index the remote peer uses
466 		// for metadata extension messages.
467 		int m_message_index;
468 
469 		// this is set to the next time we can request pieces
470 		// again. It is updated every time we get a
471 		// "I don't have metadata" message, but also when
472 		// we receive metadata that fails the infohash check
473 		time_point m_request_limit;
474 
475 		// request queues
476 		std::vector<int> m_sent_requests;
477 		std::vector<int> m_incoming_requests;
478 
479 		torrent& m_torrent;
480 		bt_peer_connection& m_pc;
481 		ut_metadata_plugin& m_tp;
482 	};
483 
new_connection(peer_connection_handle const & pc)484 	std::shared_ptr<peer_plugin> ut_metadata_plugin::new_connection(
485 		peer_connection_handle const& pc)
486 	{
487 		if (pc.type() != connection_type::bittorrent) return {};
488 
489 		bt_peer_connection* c = static_cast<bt_peer_connection*>(pc.native_handle().get());
490 		return std::make_shared<ut_metadata_peer_plugin>(m_torrent, *c, *this);
491 	}
492 
493 	// has_metadata is false if the peer making the request has not announced
494 	// that it has metadata. In this case, it shouldn't prevent other peers
495 	// from requesting this block by setting a timeout on it.
metadata_request(bool const has_metadata)496 	int ut_metadata_plugin::metadata_request(bool const has_metadata)
497 	{
498 		auto i = std::min_element(
499 			m_requested_metadata.begin(), m_requested_metadata.end());
500 
501 		if (m_requested_metadata.empty())
502 		{
503 			// if we don't know how many pieces there are
504 			// just ask for piece 0
505 			m_requested_metadata.resize(1);
506 			i = m_requested_metadata.begin();
507 		}
508 
509 		int const piece = int(i - m_requested_metadata.begin());
510 
511 		// don't request the same block more than once every 3 seconds
512 		time_point const now = aux::time_now();
513 		if (m_requested_metadata[piece].last_request != min_time()
514 			&& total_seconds(now - m_requested_metadata[piece].last_request) < 3)
515 			return -1;
516 
517 		++m_requested_metadata[piece].num_requests;
518 
519 		// only set the timeout on this block, only if the peer
520 		// has metadata. This is to prevent peers with no metadata
521 		// to starve out sending requests to peers with metadata
522 		if (has_metadata)
523 			m_requested_metadata[piece].last_request = now;
524 
525 		return piece;
526 	}
527 
received_metadata(ut_metadata_peer_plugin & source,span<char const> buf,int const piece,int const total_size)528 	bool ut_metadata_plugin::received_metadata(ut_metadata_peer_plugin& source
529 		, span<char const> buf, int const piece, int const total_size)
530 	{
531 		if (m_torrent.valid_metadata())
532 		{
533 #ifndef TORRENT_DISABLE_LOGGING
534 			source.m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
535 				, "already have metadata");
536 #endif
537 			m_torrent.add_redundant_bytes(static_cast<int>(buf.size()), waste_reason::piece_unknown);
538 			return false;
539 		}
540 
541 		if (!m_metadata)
542 		{
543 			// verify the total_size
544 			if (total_size <= 0 || total_size > m_torrent.session().settings().get_int(settings_pack::max_metadata_size))
545 			{
546 #ifndef TORRENT_DISABLE_LOGGING
547 				source.m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
548 					, "metadata size too big: %d", total_size);
549 #endif
550 // #error post alert
551 				return false;
552 			}
553 
554 			m_metadata.reset(new char[std::size_t(total_size)]);
555 			m_requested_metadata.resize(div_round_up(total_size, 16 * 1024));
556 			m_metadata_size = total_size;
557 		}
558 
559 		if (piece < 0 || piece >= m_requested_metadata.end_index())
560 		{
561 #ifndef TORRENT_DISABLE_LOGGING
562 			source.m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
563 				, "piece: %d INVALID", piece);
564 #endif
565 			return false;
566 		}
567 
568 		if (total_size != m_metadata_size)
569 		{
570 #ifndef TORRENT_DISABLE_LOGGING
571 			source.m_pc.peer_log(peer_log_alert::info, "UT_METADATA"
572 				, "total_size: %d INCONSISTENT WITH: %d"
573 				, total_size, m_metadata_size);
574 #endif
575 			// they disagree about the size!
576 			return false;
577 		}
578 
579 		if (piece * 16 * 1024 + buf.size() > m_metadata_size)
580 		{
581 			// this piece is invalid
582 			return false;
583 		}
584 
585 		std::memcpy(&m_metadata[piece * 16 * 1024], buf.data(), aux::numeric_cast<std::size_t>(buf.size()));
586 		// mark this piece has 'have'
587 		m_requested_metadata[piece].num_requests = std::numeric_limits<int>::max();
588 		m_requested_metadata[piece].source = source.shared_from_this();
589 
590 		bool have_all = std::all_of(m_requested_metadata.begin(), m_requested_metadata.end()
591 			, [](metadata_piece const& mp) { return mp.num_requests == std::numeric_limits<int>::max(); });
592 
593 		if (!have_all) return false;
594 
595 		if (!m_torrent.set_metadata({m_metadata.get(), m_metadata_size}))
596 		{
597 			if (!m_torrent.valid_metadata())
598 			{
599 				time_point const now = aux::time_now();
600 				// any peer that we downloaded metadata from gets a random time
601 				// penalty, from 5 to 30 seconds or so. During this time we don't
602 				// make any metadata requests from those peers (to mix it up a bit
603 				// of which peers we use)
604 				// if we only have one block, and thus requested it from a single
605 				// peer, we bump up the retry time a lot more to try other peers
606 				bool single_peer = m_requested_metadata.size() == 1;
607 				for (auto& mp : m_requested_metadata)
608 				{
609 					mp.num_requests = 0;
610 					auto peer = mp.source.lock();
611 					if (!peer) continue;
612 
613 					peer->failed_hash_check(single_peer ? now + minutes(5) : now);
614 				}
615 			}
616 			return false;
617 		}
618 
619 		// free our copy of the metadata and get a reference
620 		// to the torrent's copy instead. No need to keep two
621 		// identical copies around
622 		m_metadata.reset();
623 		metadata();
624 
625 		// clear the storage for the bitfield
626 		m_requested_metadata.clear();
627 		m_requested_metadata.shrink_to_fit();
628 
629 		return true;
630 	}
631 
632 } }
633 
634 namespace libtorrent {
635 
create_ut_metadata_plugin(torrent_handle const & th,void *)636 	std::shared_ptr<torrent_plugin> create_ut_metadata_plugin(torrent_handle const& th, void*)
637 	{
638 		torrent* t = th.native_handle().get();
639 		// don't add this extension if the torrent is private
640 		if (t->valid_metadata() && t->torrent_file().priv()) return {};
641 		return std::make_shared<ut_metadata_plugin>(*t);
642 	}
643 }
644 
645 #endif
646