file_progress fix
[libtorrent.git] / src / metadata_transfer.cpp
bloba347223e345a065e44695cb1111cc32fc5308da1
1 /*
3 Copyright (c) 2006, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
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.
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.
33 #include "libtorrent/pch.hpp"
35 #ifdef _MSC_VER
36 #pragma warning(push, 1)
37 #endif
39 #include <boost/shared_ptr.hpp>
40 #include <boost/lexical_cast.hpp>
42 #ifdef _MSC_VER
43 #pragma warning(pop)
44 #endif
46 #include <vector>
47 #include <utility>
48 #include <numeric>
50 #include "libtorrent/peer_connection.hpp"
51 #include "libtorrent/bt_peer_connection.hpp"
52 #include "libtorrent/hasher.hpp"
53 #include "libtorrent/bencode.hpp"
54 #include "libtorrent/torrent.hpp"
55 #include "libtorrent/extensions.hpp"
56 #include "libtorrent/extensions/metadata_transfer.hpp"
57 #include "libtorrent/alert_types.hpp"
58 #include "libtorrent/buffer.hpp"
60 namespace libtorrent { namespace
62 int div_round_up(int numerator, int denominator)
64 return (numerator + denominator - 1) / denominator;
67 std::pair<int, int> req_to_offset(std::pair<int, int> req, int total_size)
69 TORRENT_ASSERT(req.first >= 0);
70 TORRENT_ASSERT(req.second > 0);
71 TORRENT_ASSERT(req.second <= 256);
72 TORRENT_ASSERT(req.first + req.second <= 256);
74 int start = div_round_up(req.first * total_size, 256);
75 int size = div_round_up((req.first + req.second) * total_size, 256) - start;
76 return std::make_pair(start, size);
79 std::pair<int, int> offset_to_req(std::pair<int, int> offset, int total_size)
81 int start = offset.first * 256 / total_size;
82 int size = (offset.first + offset.second) * 256 / total_size - start;
84 std::pair<int, int> ret(start, size);
86 TORRENT_ASSERT(start >= 0);
87 TORRENT_ASSERT(size > 0);
88 TORRENT_ASSERT(start <= 256);
89 TORRENT_ASSERT(start + size <= 256);
91 // assert the identity of this function
92 #ifndef NDEBUG
93 std::pair<int, int> identity = req_to_offset(ret, total_size);
94 TORRENT_ASSERT(offset == identity);
95 #endif
96 return ret;
99 struct metadata_plugin : torrent_plugin
101 metadata_plugin(torrent& t)
102 : m_torrent(t)
103 , m_metadata_progress(0)
104 , m_metadata_size(0)
106 m_requested_metadata.resize(256, 0);
109 virtual void on_files_checked()
111 // if the torrent is a seed, make a reference to
112 // the metadata from the torrent before it is deallocated
113 if (m_torrent.is_seed()) metadata();
116 virtual boost::shared_ptr<peer_plugin> new_connection(
117 peer_connection* pc);
119 buffer::const_interval metadata() const
121 if (!m_metadata)
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());
128 return buffer::const_interval(m_metadata.get(), m_metadata.get()
129 + m_metadata_size);
132 bool received_metadata(char const* buf, int size, int offset, int total_size)
134 if (m_torrent.valid_metadata()) return false;
136 if (!m_metadata || m_metadata_size < total_size)
138 m_metadata.reset(new char[total_size]);
139 m_metadata_size = total_size;
141 std::copy(buf, buf + size, &m_metadata[offset]);
143 if (m_have_metadata.empty())
144 m_have_metadata.resize(256, false);
146 std::pair<int, int> req = offset_to_req(std::make_pair(offset, size)
147 , total_size);
149 TORRENT_ASSERT(req.first + req.second <= (int)m_have_metadata.size());
151 std::fill(
152 m_have_metadata.begin() + req.first
153 , m_have_metadata.begin() + req.first + req.second
154 , true);
156 bool have_all = std::count(
157 m_have_metadata.begin()
158 , m_have_metadata.end()
159 , true) == 256;
161 if (!have_all) return false;
163 hasher h;
164 h.update(&m_metadata[0], m_metadata_size);
165 sha1_hash info_hash = h.final();
167 if (info_hash != m_torrent.torrent_file().info_hash())
169 std::fill(
170 m_have_metadata.begin()
171 , m_have_metadata.begin() + req.first + req.second
172 , false);
173 m_metadata_progress = 0;
174 m_metadata_size = 0;
176 if (m_torrent.alerts().should_post<metadata_failed_alert>())
178 m_torrent.alerts().post_alert(metadata_failed_alert(
179 m_torrent.get_handle()));
182 return false;
185 lazy_entry e;
186 lazy_bdecode(m_metadata.get(), m_metadata.get() + m_metadata_size, e);
187 std::string error;
188 if (!m_torrent.set_metadata(e, error))
190 // this means the metadata is correct, since we
191 // verified it against the info-hash, but we
192 // failed to parse it. Pause the torrent
193 // TODO: Post an alert!
194 m_torrent.pause();
195 return false;
198 // clear the storage for the bitfield
199 std::vector<bool>().swap(m_have_metadata);
200 std::vector<int>().swap(m_requested_metadata);
202 return true;
205 // returns a range of the metadata that
206 // we should request.
207 std::pair<int, int> metadata_request();
209 void cancel_metadata_request(std::pair<int, int> req)
211 for (int i = req.first; i < req.first + req.second; ++i)
213 TORRENT_ASSERT(m_requested_metadata[i] > 0);
214 if (m_requested_metadata[i] > 0)
215 --m_requested_metadata[i];
219 // this is called from the peer_connection for
220 // each piece of metadata it receives
221 void metadata_progress(int total_size, int received)
223 m_metadata_progress += received;
224 m_metadata_size = total_size;
227 void on_piece_pass(int)
229 // if we became a seed, copy the metadata from
230 // the torrent before it is deallocated
231 if (m_torrent.is_seed())
232 metadata();
235 private:
236 torrent& m_torrent;
238 // this buffer is filled with the info-section of
239 // the metadata file while downloading it from
240 // peers, and while sending it.
241 // it is mutable because it's generated lazily
242 mutable boost::shared_array<char> m_metadata;
244 int m_metadata_progress;
245 mutable int m_metadata_size;
247 // this is a bitfield of size 256, each bit represents
248 // a piece of the metadata. It is set to one if we
249 // have that piece. This vector may be empty
250 // (size 0) if we haven't received any metadata
251 // or if we already have all metadata
252 std::vector<bool> m_have_metadata;
253 // this vector keeps track of how many times each meatdata
254 // block has been requested
255 std::vector<int> m_requested_metadata;
259 struct metadata_peer_plugin : peer_plugin
261 metadata_peer_plugin(torrent& t, peer_connection& pc
262 , metadata_plugin& tp)
263 : m_waiting_metadata_request(false)
264 , m_message_index(0)
265 , m_metadata_progress(0)
266 , m_no_metadata(min_time())
267 , m_metadata_request(min_time())
268 , m_torrent(t)
269 , m_pc(pc)
270 , m_tp(tp)
273 // can add entries to the extension handshake
274 virtual void add_handshake(entry& h)
276 entry& messages = h["m"];
277 messages["LT_metadata"] = 14;
280 // called when the extension handshake from the other end is received
281 virtual bool on_extension_handshake(lazy_entry const& h)
283 m_message_index = 0;
284 if (h.type() != lazy_entry::dict_t) return false;
285 lazy_entry const* messages = h.dict_find("m");
286 if (!messages || messages->type() != lazy_entry::dict_t) return false;
288 int index = messages->dict_find_int_value("LT_metadata", -1);
289 if (index == -1) return false;
290 m_message_index = index;
291 return true;
294 void write_metadata_request(std::pair<int, int> req)
296 TORRENT_ASSERT(req.first >= 0);
297 TORRENT_ASSERT(req.second > 0);
298 TORRENT_ASSERT(req.first + req.second <= 256);
299 TORRENT_ASSERT(!m_pc.associated_torrent().expired());
300 TORRENT_ASSERT(!m_pc.associated_torrent().lock()->valid_metadata());
302 int start = req.first;
303 int size = req.second;
305 // abort if the peer doesn't support the metadata extension
306 if (m_message_index == 0) return;
308 buffer::interval i = m_pc.allocate_send_buffer(9);
310 detail::write_uint32(1 + 1 + 3, i.begin);
311 detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
312 detail::write_uint8(m_message_index, i.begin);
313 // means 'request data'
314 detail::write_uint8(0, i.begin);
315 detail::write_uint8(start, i.begin);
316 detail::write_uint8(size - 1, i.begin);
317 TORRENT_ASSERT(i.begin == i.end);
318 m_pc.setup_send();
321 void write_metadata(std::pair<int, int> req)
323 TORRENT_ASSERT(req.first >= 0);
324 TORRENT_ASSERT(req.second > 0);
325 TORRENT_ASSERT(req.second <= 256);
326 TORRENT_ASSERT(req.first + req.second <= 256);
327 TORRENT_ASSERT(!m_pc.associated_torrent().expired());
329 // abort if the peer doesn't support the metadata extension
330 if (m_message_index == 0) return;
332 // only send metadata if the torrent is non-private
333 if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv())
335 std::pair<int, int> offset
336 = req_to_offset(req, (int)m_tp.metadata().left());
338 buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second);
340 // yes, we have metadata, send it
341 detail::write_uint32(11 + offset.second, i.begin);
342 detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
343 detail::write_uint8(m_message_index, i.begin);
344 // means 'data packet'
345 detail::write_uint8(1, i.begin);
346 detail::write_uint32((int)m_tp.metadata().left(), i.begin);
347 detail::write_uint32(offset.first, i.begin);
348 char const* metadata = m_tp.metadata().begin;
349 std::copy(metadata + offset.first
350 , metadata + offset.first + offset.second, i.begin);
351 i.begin += offset.second;
352 TORRENT_ASSERT(i.begin == i.end);
354 else
356 buffer::interval i = m_pc.allocate_send_buffer(4 + 3);
357 // we don't have the metadata, reply with
358 // don't have-message
359 detail::write_uint32(1 + 2, i.begin);
360 detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
361 detail::write_uint8(m_message_index, i.begin);
362 // means 'have no data'
363 detail::write_uint8(2, i.begin);
364 TORRENT_ASSERT(i.begin == i.end);
366 m_pc.setup_send();
369 virtual bool on_extended(int length
370 , int msg, buffer::const_interval body)
372 if (msg != 14) return false;
373 if (m_message_index == 0) return false;
375 if (length > 500 * 1024)
377 m_pc.disconnect("LT_metadata message larger than 500 kB");
378 return true;
381 if (body.left() < 1) return true;
382 int type = detail::read_uint8(body.begin);
384 switch (type)
386 case 0: // request
388 if (body.left() < 2) return true;
389 int start = detail::read_uint8(body.begin);
390 int size = detail::read_uint8(body.begin) + 1;
392 if (length != 3)
394 // invalid metadata request
395 m_pc.disconnect("invalid metadata request");
396 return true;
399 write_metadata(std::make_pair(start, size));
401 break;
402 case 1: // data
404 if (body.left() < 8) return true;
406 int total_size = detail::read_int32(body.begin);
407 int offset = detail::read_int32(body.begin);
408 int data_size = length - 9;
410 if (total_size > 500 * 1024)
412 m_pc.disconnect("metadata size larger than 500 kB");
413 return true;
415 if (total_size <= 0)
417 m_pc.disconnect("invalid metadata size");
418 return true;
420 if (offset > total_size || offset < 0)
422 m_pc.disconnect("invalid metadata offset");
423 return true;
425 if (offset + data_size > total_size)
427 m_pc.disconnect("invalid metadata message");
428 return true;
431 m_tp.metadata_progress(total_size
432 , body.left() - m_metadata_progress);
433 m_metadata_progress = body.left();
435 if (body.left() < data_size) return true;
437 m_waiting_metadata_request = false;
438 m_tp.received_metadata(body.begin, data_size
439 , offset, total_size);
440 m_metadata_progress = 0;
442 break;
443 case 2: // have no data
444 m_no_metadata = time_now();
445 if (m_waiting_metadata_request)
446 m_tp.cancel_metadata_request(m_last_metadata_request);
447 m_waiting_metadata_request = false;
448 break;
449 default:
451 std::stringstream msg;
452 msg << "unknown metadata extension message: " << type;
453 m_pc.disconnect(msg.str().c_str());
456 return true;
459 virtual void tick()
461 // if we don't have any metadata, and this peer
462 // supports the request metadata extension
463 // and we aren't currently waiting for a request
464 // reply. Then, send a request for some metadata.
465 if (!m_torrent.valid_metadata()
466 && m_message_index != 0
467 && !m_waiting_metadata_request
468 && has_metadata())
470 m_last_metadata_request = m_tp.metadata_request();
471 write_metadata_request(m_last_metadata_request);
472 m_waiting_metadata_request = true;
473 m_metadata_request = time_now();
477 bool has_metadata() const
479 return time_now() - m_no_metadata > minutes(5);
482 private:
484 // this is set to true when we send a metadata
485 // request to this peer, and reset to false when
486 // we receive a reply to our request.
487 bool m_waiting_metadata_request;
489 // this is the message index the remote peer uses
490 // for metadata extension messages.
491 int m_message_index;
493 // the number of bytes of metadata we have received
494 // so far from this per, only counting the current
495 // request. Any previously finished requests
496 // that have been forwarded to the torrent object
497 // do not count.
498 int m_metadata_progress;
500 // this is set to the current time each time we get a
501 // "I don't have metadata" message.
502 ptime m_no_metadata;
504 // this is set to the time when we last sent
505 // a request for metadata to this peer
506 ptime m_metadata_request;
508 // if we're waiting for a metadata request
509 // this was the request we sent
510 std::pair<int, int> m_last_metadata_request;
512 torrent& m_torrent;
513 peer_connection& m_pc;
514 metadata_plugin& m_tp;
517 boost::shared_ptr<peer_plugin> metadata_plugin::new_connection(
518 peer_connection* pc)
520 bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
521 if (!c) return boost::shared_ptr<peer_plugin>();
522 return boost::shared_ptr<peer_plugin>(new metadata_peer_plugin(m_torrent, *pc, *this));
525 std::pair<int, int> metadata_plugin::metadata_request()
527 // count the number of peers that supports the
528 // extension and that has metadata
529 int peers = 0;
530 #ifndef TORRENT_DISABLE_EXTENSIONS
531 for (torrent::peer_iterator i = m_torrent.begin()
532 , end(m_torrent.end()); i != end; ++i)
534 bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(*i);
535 if (c == 0) continue;
536 metadata_peer_plugin* p
537 = c->supports_extension<metadata_peer_plugin>();
538 if (p == 0) continue;
539 if (!p->has_metadata()) continue;
540 ++peers;
542 #endif
544 // the number of blocks to request
545 int num_blocks = 256 / (peers + 1);
546 if (num_blocks < 1) num_blocks = 1;
547 TORRENT_ASSERT(num_blocks <= 128);
549 int min_element = (std::numeric_limits<int>::max)();
550 int best_index = 0;
551 for (int i = 0; i < 256 - num_blocks + 1; ++i)
553 int min = *std::min_element(m_requested_metadata.begin() + i
554 , m_requested_metadata.begin() + i + num_blocks);
555 min += std::accumulate(m_requested_metadata.begin() + i
556 , m_requested_metadata.begin() + i + num_blocks, (int)0);
558 if (min_element > min)
560 best_index = i;
561 min_element = min;
565 std::pair<int, int> ret(best_index, num_blocks);
566 for (int i = ret.first; i < ret.first + ret.second; ++i)
567 m_requested_metadata[i]++;
569 TORRENT_ASSERT(ret.first >= 0);
570 TORRENT_ASSERT(ret.second > 0);
571 TORRENT_ASSERT(ret.second <= 256);
572 TORRENT_ASSERT(ret.first + ret.second <= 256);
574 return ret;
579 namespace libtorrent
582 boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent* t, void*)
584 return boost::shared_ptr<torrent_plugin>(new metadata_plugin(*t));