1 // rTorrent - BitTorrent client
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL.  If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so.  If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact:  Jari Sundell <jaris@ifi.uio.no>
33 //
34 //           Skomakerveien 33
35 //           3185 Skoppum, NORWAY
36 
37 #include "config.h"
38 
39 #include <algorithm>
40 #include <fstream>
41 #include <iostream>
42 #include <rak/functional.h>
43 #include <rak/string_manip.h>
44 #include <torrent/data/file.h>
45 #include <torrent/utils/resume.h>
46 #include <torrent/exceptions.h>
47 #include <torrent/download.h>
48 #include <torrent/hash_string.h>
49 #include <torrent/object.h>
50 #include <torrent/object_stream.h>
51 #include <torrent/torrent.h>
52 #include <torrent/utils/log.h>
53 
54 #include "rpc/parse_commands.h"
55 
56 #include "control.h"
57 #include "globals.h"
58 #include "manager.h"
59 #include "view.h"
60 #include "view_manager.h"
61 
62 #include "dht_manager.h"
63 #include "download.h"
64 #include "download_list.h"
65 #include "download_store.h"
66 #include "ui/root.h"
67 
68 #define DL_TRIGGER_EVENT(download, event_name) \
69   rpc::commands.call_catch(event_name, rpc::make_target(download), torrent::Object(), "Event '" event_name "' failed: ");
70 
71 namespace core {
72 
73 inline void
check_contains(Download * d)74 DownloadList::check_contains(Download* d) {
75 #ifdef USE_EXTRA_DEBUG
76   if (std::find(begin(), end(), d) == end())
77     throw torrent::internal_error("DownloadList::check_contains(...) failed.");
78 #endif
79 }
80 
81 void
clear()82 DownloadList::clear() {
83   std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadList::close), this));
84   std::for_each(begin(), end(), rak::call_delete<Download>());
85 
86   base_type::clear();
87 }
88 
89 void
session_save()90 DownloadList::session_save() {
91   unsigned int c = std::count_if(begin(), end(), std::bind1st(std::mem_fun(&DownloadStore::save_resume), control->core()->download_store()));
92 
93   if (c != size())
94     lt_log_print(torrent::LOG_ERROR, "Failed to save session torrents.");
95 
96   control->dht_manager()->save_dht_cache();
97   control->ui()->save_input_history();
98 }
99 
100 DownloadList::iterator
find(const torrent::HashString & hash)101 DownloadList::find(const torrent::HashString& hash) {
102   return std::find_if(begin(), end(), rak::equal(hash, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
103 }
104 
105 DownloadList::iterator
find_hex(const char * hash)106 DownloadList::find_hex(const char* hash) {
107   torrent::HashString key;
108 
109   for (torrent::HashString::iterator itr = key.begin(), last = key.end(); itr != last; itr++, hash += 2)
110     *itr = (rak::hexchar_to_value(*hash) << 4) + rak::hexchar_to_value(*(hash + 1));
111 
112   return std::find_if(begin(), end(), rak::equal(key, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
113 }
114 
115 Download*
find_hex_ptr(const char * hash)116 DownloadList::find_hex_ptr(const char* hash) {
117   iterator itr = find_hex(hash);
118 
119   return itr != end() ? *itr : NULL;
120 }
121 
122 Download*
create(torrent::Object * obj,bool printLog)123 DownloadList::create(torrent::Object* obj, bool printLog) {
124   torrent::Download download;
125 
126   try {
127     download = torrent::download_add(obj);
128 
129   } catch (torrent::local_error& e) {
130     delete obj;
131 
132     if (printLog)
133       lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
134 
135     return NULL;
136   }
137 
138   // There's no non-critical exceptions that should be throwable by
139   // the ctor, so don't catch.
140   return new Download(download);
141 }
142 
143 Download*
create(std::istream * str,bool printLog)144 DownloadList::create(std::istream* str, bool printLog) {
145   torrent::Object* object = new torrent::Object;
146   torrent::Download download;
147 
148   try {
149     *str >> *object;
150 
151     // Don't throw input_error from here as gcc-3.3.5 produces bad
152     // code.
153     if (str->fail()) {
154       delete object;
155 
156       if (printLog)
157         lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
158 
159       return NULL;
160     }
161 
162     download = torrent::download_add(object);
163 
164   } catch (torrent::local_error& e) {
165     delete object;
166 
167     if (printLog)
168       lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
169 
170     return NULL;
171   }
172 
173   // There's no non-critical exceptions that should be throwable by
174   // the ctor, so don't catch.
175   return new Download(download);
176 }
177 
178 DownloadList::iterator
insert(Download * download)179 DownloadList::insert(Download* download) {
180   iterator itr = base_type::insert(end(), download);
181 
182   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download.");
183 
184   try {
185     (*itr)->data()->slot_initial_hash()        = std::bind(&DownloadList::hash_done, this, download);
186     (*itr)->data()->slot_download_done()       = std::bind(&DownloadList::received_finished, this, download);
187 
188     // This needs to be separated into two different calls to ensure
189     // the download remains in the view.
190     std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::insert), download));
191     std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::filter_download), download));
192 
193     DL_TRIGGER_EVENT(*itr, "event.download.inserted");
194 
195   } catch (torrent::local_error& e) {
196     // Should perhaps relax this, just print an error and remove the
197     // downloads?
198     throw torrent::internal_error("Caught during DownloadList::insert(...): " + std::string(e.what()));
199   }
200 
201   return itr;
202 }
203 
204 void
erase_ptr(Download * download)205 DownloadList::erase_ptr(Download* download) {
206   erase(std::find(begin(), end(), download));
207 }
208 
209 DownloadList::iterator
erase(iterator itr)210 DownloadList::erase(iterator itr) {
211   if (itr == end())
212     throw torrent::internal_error("DownloadList::erase(...) could not find download.");
213 
214   lt_log_print_info(torrent::LOG_TORRENT_INFO, (*itr)->info(), "download_list", "Erasing download.");
215 
216   // Makes sure close doesn't restart hashing of this download.
217   (*itr)->set_hash_failed(true);
218 
219   close(*itr);
220 
221   control->core()->download_store()->remove(*itr);
222 
223   DL_TRIGGER_EVENT(*itr, "event.download.erased");
224   std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr));
225 
226   torrent::download_remove(*(*itr)->download());
227   delete *itr;
228 
229   return base_type::erase(itr);
230 }
231 
232 bool
open(Download * download)233 DownloadList::open(Download* download) {
234   try {
235 
236     open_throw(download);
237 
238     return true;
239 
240   } catch (torrent::local_error& e) {
241     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not open download: %s", e.what());
242     return false;
243   }
244 }
245 
246 void
open_throw(Download * download)247 DownloadList::open_throw(Download* download) {
248   check_contains(download);
249 
250   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Opening download.");
251 
252   if (download->download()->info()->is_open())
253     return;
254 
255   int openFlags = download->resume_flags();
256 
257   if (rpc::call_command_value("system.file.allocate"))
258     openFlags |= torrent::Download::open_enable_fallocate;
259 
260   download->download()->open(openFlags);
261   DL_TRIGGER_EVENT(download, "event.download.opened");
262 }
263 
264 void
close(Download * download)265 DownloadList::close(Download* download) {
266   try {
267     close_throw(download);
268 
269   } catch (torrent::local_error& e) {
270     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not close download: %s", e.what());
271   }
272 }
273 
274 void
close_directly(Download * download)275 DownloadList::close_directly(Download* download) {
276   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download directly.");
277 
278   if (download->download()->info()->is_active()) {
279     download->download()->stop(torrent::Download::stop_skip_tracker);
280 
281     if (torrent::resume_check_target_files(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")))
282       torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
283   }
284 
285   if (download->download()->info()->is_open())
286     download->download()->close();
287 }
288 
289 void
close_quick(Download * download)290 DownloadList::close_quick(Download* download) {
291   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download quickly.");
292   close(download);
293 
294   // Make sure we cancel any tracker requests. This should rather be
295   // handled by some parameter to the close function, or some other
296   // way of giving the client more control of when STOPPED requests
297   // are sent.
298   download->download()->manual_cancel();
299 }
300 
301 void
close_throw(Download * download)302 DownloadList::close_throw(Download* download) {
303   check_contains(download);
304 
305   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download with throw.");
306 
307   // When pause gets called it will clear the initial hash check state
308   // and set hash failed. This should ensure hashing doesn't restart
309   // until resume gets called.
310   pause(download);
311 
312   // Check for is_open after pause due to hashing.
313   if (!download->is_open())
314     return;
315 
316   // Save the torrent on close, this covers shutdown and if a torrent
317   // is manually closed which would clear the progress data. For
318   // better crash protection, save regulary in addition to this.
319   //
320   // Used to be in pause, but this was wrong for rehashing etc.
321   //
322   // Reconsider this save. Should be done explicitly when shutting down.
323   //control->core()->download_store()->save(download);
324 
325   download->download()->close();
326 
327   if (!download->is_hash_failed() && rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
328     throw torrent::internal_error("DownloadList::close_throw(...) called but we're going into a hashing loop.");
329 
330   DL_TRIGGER_EVENT(download, "event.download.hash_removed");
331   DL_TRIGGER_EVENT(download, "event.download.closed");
332 }
333 
334 void
resume(Download * download,int flags)335 DownloadList::resume(Download* download, int flags) {
336   check_contains(download);
337 
338   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Resuming download: flags:%0x.", flags);
339 
340   try {
341 
342     if (download->download()->info()->is_active())
343       return;
344 
345     rpc::parse_command_single(rpc::make_target(download), "view.set_visible=active");
346 
347     // We need to make sure the flags aren't reset if someone decideds
348     // to call resume() while it is hashing, etc.
349     if (download->resume_flags() == ~uint32_t())
350       download->set_resume_flags(flags);
351 
352     // Manual or end-of-download rehashing clears the resume data so
353     // we can just start the hashing again without clearing it again.
354     //
355     // It is also assumed the is_hash_checked flag gets cleared when
356     // 'hashing' was set.
357     if (!download->is_hash_checked()) {
358       // If the hash failed flag wasn't cleared then hashing won't be
359       // initiated.
360       if (download->is_hash_failed())
361         return;
362 
363       if (rpc::call_command_value("d.hashing", rpc::make_target(download)) == Download::variable_hashing_stopped)
364         rpc::call_command("d.hashing.set", Download::variable_hashing_initial, rpc::make_target(download));
365 
366       DL_TRIGGER_EVENT(download, "event.download.hash_queued");
367       return;
368     }
369 
370     // This will never actually do anything due to the above hash check.
371     // open_throw(download);
372 
373     rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download));
374     rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)) + 1, rpc::make_target(download));
375 
376     if (download->is_done()) {
377       torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download));
378       torrent::Object choke_up     = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
379       torrent::Object choke_down   = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
380 
381       if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download));
382       if (choke_up.is_string_empty())     choke_up     = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download));
383       if (choke_down.is_string_empty())   choke_down   = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download));
384 
385       rpc::call_command("d.connection_current.set",    conn_current, rpc::make_target(download));
386       rpc::call_command("d.up.choke_heuristics.set",   choke_up, rpc::make_target(download));
387       rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download));
388 
389     } else {
390       torrent::Object conn_current = rpc::call_command("d.connection_leech", torrent::Object(), rpc::make_target(download));
391       torrent::Object choke_up     = rpc::call_command("d.up.choke_heuristics.leech", torrent::Object(), rpc::make_target(download));
392       torrent::Object choke_down   = rpc::call_command("d.down.choke_heuristics.leech", torrent::Object(), rpc::make_target(download));
393 
394       if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.leech", torrent::Object(), rpc::make_target(download));
395       if (choke_up.is_string_empty())     choke_up     = rpc::call_command("protocol.choke_heuristics.up.leech", torrent::Object(), rpc::make_target(download));
396       if (choke_down.is_string_empty())   choke_down   = rpc::call_command("protocol.choke_heuristics.down.leech", torrent::Object(), rpc::make_target(download));
397 
398       rpc::call_command("d.connection_current.set",    conn_current, rpc::make_target(download));
399       rpc::call_command("d.up.choke_heuristics.set",   choke_up, rpc::make_target(download));
400       rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download));
401 
402       // For the moment, clear the resume data so we force hash-check
403       // on non-complete downloads after a crash. This shouldn't be
404       // needed, but for some reason linux 2.6 is very lazy about
405       // updating mtime.
406       //
407       // Disabling this due to the new resume code.
408       //      torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"), true);
409     }
410 
411     // If the DHT server is set to auto, start it now.
412     if (!download->download()->info()->is_private())
413       control->dht_manager()->auto_start();
414 
415     // Update the priority to ensure it has the correct
416     // seeding/unfinished modifiers.
417     download->set_priority(download->priority());
418     download->download()->start(download->resume_flags());
419 
420     download->set_resume_flags(~uint32_t());
421 
422     DL_TRIGGER_EVENT(download, "event.download.resumed");
423 
424   } catch (torrent::local_error& e) {
425     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not resume download: %s", e.what());
426   }
427 }
428 
429 void
pause(Download * download,int flags)430 DownloadList::pause(Download* download, int flags) {
431   check_contains(download);
432 
433   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Pausing download: flags:%0x.", flags);
434 
435   try {
436 
437     download->set_resume_flags(~uint32_t());
438 
439     rpc::parse_command_single(rpc::make_target(download), "view.set_not_visible=active");
440 
441     // Always clear hashing on pause. When a hashing request is added,
442     // it should have cleared the hash resume data.
443     if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped) {
444       download->download()->hash_stop();
445       rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_stopped, rpc::make_target(download));
446 
447       DL_TRIGGER_EVENT(download, "event.download.hash_removed");
448     }
449 
450     if (!download->download()->info()->is_active())
451       return;
452 
453     download->download()->stop(flags);
454     torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
455 
456     // TODO: This is actually for pause, not stop... And doesn't get
457     // called when the download isn't active, but was in the 'started'
458     // view.
459     DL_TRIGGER_EVENT(download, "event.download.paused");
460 
461     rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download));
462     rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)), rpc::make_target(download));
463 
464     // If initial seeding is complete, don't try it again when restarting.
465     if (download->is_done() &&
466         rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)).as_string() == "initial_seed")
467       rpc::call_command("d.connection_seed.set", rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)), rpc::make_target(download));
468 
469     // Save the state after all the slots, etc have been called so we
470     // include the modifications they may make.
471     //control->core()->download_store()->save(download);
472 
473   } catch (torrent::local_error& e) {
474     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not pause download: %s", e.what());
475   }
476 }
477 
478 void
check_hash(Download * download)479 DownloadList::check_hash(Download* download) {
480   check_contains(download);
481 
482   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Checking hash.");
483 
484   try {
485     if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
486       return;
487 
488     hash_queue(download, Download::variable_hashing_rehash);
489 
490   } catch (torrent::local_error& e) {
491     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not check hash: %s", e.what());
492   }
493 }
494 
495 void
hash_done(Download * download)496 DownloadList::hash_done(Download* download) {
497   check_contains(download);
498 
499   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash done.");
500 
501   if (download->is_hash_checking() || download->is_active())
502     throw torrent::internal_error("DownloadList::hash_done(...) download in invalid state.");
503 
504   if (!download->is_hash_checked()) {
505     download->set_hash_failed(true);
506 
507     DL_TRIGGER_EVENT(download, "event.download.hash_failed");
508     return;
509   }
510 
511   // Need to find some sane conditional here. Can we check the total
512   // downloaded to ensure something was transferred, thus we didn't
513   // just hash an already completed torrent with lacking session data?
514   //
515   // Perhaps we should use a seperate variable or state, and check
516   // that. Thus we can bork the download if the hash check doesn't
517   // confirm all the data, avoiding large BW usage on f.ex. the
518   // ReiserFS bug with >4GB files.
519 
520   int64_t hashing = rpc::call_command_value("d.hashing", rpc::make_target(download));
521   rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_stopped, rpc::make_target(download));
522 
523   if (download->is_done() && download->download()->info()->is_meta_download())
524     return process_meta_download(download);
525 
526   switch (hashing) {
527   case Download::variable_hashing_initial:
528   case Download::variable_hashing_rehash:
529     // Normal re/hashing.
530 
531     // If the download was previously completed but the files were
532     // f.ex deleted, then we clear the state and complete.
533     if (rpc::call_command_value("d.complete", rpc::make_target(download)) && !download->is_done()) {
534       rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(download));
535       download->set_message("Download registered as completed, but hash check returned unfinished chunks.");
536     }
537 
538     // Save resume data so we update time-stamps and priorities if
539     // they were invalid/changed while loading/hashing.
540     rpc::call_command("d.complete.set", (int64_t)download->is_done(), rpc::make_target(download));
541     torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
542 
543     if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
544       resume(download, download->resume_flags());
545 
546     break;
547 
548   case Download::variable_hashing_last:
549 
550     if (download->is_done()) {
551       confirm_finished(download);
552     } else {
553       download->set_message("Hash check on download completion found bad chunks, consider using \"safe_sync\".");
554       lt_log_print(torrent::LOG_TORRENT_ERROR, "Hash check on download completion found bad chunks, consider using \"safe_sync\".");
555       DL_TRIGGER_EVENT(download, "event.download.hash_final_failed");
556     }
557 
558     // TODO: Should we skip the 'hash_done' event here?
559     return;
560 
561   case Download::variable_hashing_stopped:
562   default:
563     // Either an error or someone wrote to the hashing variable...
564     download->set_message("Hash check completed but the \"hashing\" variable is in an invalid state.");
565     return;
566   }
567 
568   DL_TRIGGER_EVENT(download, "event.download.hash_done");
569 }
570 
571 void
hash_queue(Download * download,int type)572 DownloadList::hash_queue(Download* download, int type) {
573   check_contains(download);
574 
575   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash queue.");
576 
577   if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
578     throw torrent::internal_error("DownloadList::hash_queue(...) hashing already queued.");
579 
580   // HACK
581   if (download->is_open()) {
582     pause(download, torrent::Download::stop_skip_tracker);
583     download->download()->close();
584 
585     DL_TRIGGER_EVENT(download, "event.download.hash_removed");
586     DL_TRIGGER_EVENT(download, "event.download.closed");
587   }
588 
589   torrent::resume_clear_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
590 
591   download->set_hash_failed(false);
592   rpc::call_command_set_value("d.hashing.set", type, rpc::make_target(download));
593 
594   if (download->is_open())
595     throw torrent::internal_error("DownloadList::hash_clear(...) download still open.");
596 
597   // If any more stuff is added here, make sure resume etc are still
598   // correct.
599   DL_TRIGGER_EVENT(download, "event.download.hash_queued");
600 }
601 
602 void
received_finished(Download * download)603 DownloadList::received_finished(Download* download) {
604   check_contains(download);
605 
606   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Received finished.");
607 
608   if (rpc::call_command_value("pieces.hash.on_completion"))
609     // Set some 'checking_finished_thingie' variable to make hash_done
610     // trigger correctly, also so it can bork on missing data.
611     hash_queue(download, Download::variable_hashing_last);
612   else
613     confirm_finished(download);
614 }
615 
616 // The download must be open when we call this function.
617 void
confirm_finished(Download * download)618 DownloadList::confirm_finished(Download* download) {
619   check_contains(download);
620 
621   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Confirming finished.");
622 
623   if (download->download()->info()->is_meta_download())
624     return process_meta_download(download);
625 
626   rpc::call_command("d.complete.set", (int64_t)1, rpc::make_target(download));
627 
628   // Clean up these settings:
629   torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download));
630   torrent::Object choke_up     = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
631   torrent::Object choke_down   = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
632 
633   if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download));
634   if (choke_up.is_string_empty())     choke_up     = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download));
635   if (choke_down.is_string_empty())   choke_down   = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download));
636 
637   rpc::call_command("d.connection_current.set",    conn_current, rpc::make_target(download));
638   rpc::call_command("d.up.choke_heuristics.set",   choke_up, rpc::make_target(download));
639   rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download));
640 
641   download->set_priority(download->priority());
642 
643   if (rpc::call_command_value("d.peers_min", rpc::make_target(download)) == rpc::call_command_value("throttle.min_peers.normal") &&
644       rpc::call_command_value("throttle.min_peers.seed") >= 0)
645     rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.seed"), rpc::make_target(download));
646 
647   if (rpc::call_command_value("d.peers_max", rpc::make_target(download)) == rpc::call_command_value("throttle.max_peers.normal") &&
648       rpc::call_command_value("throttle.max_peers.seed") >= 0)
649     rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
650 
651   // Do this before the slots are called in case one of them closes
652   // the download.
653   //
654   // Obsolete.
655   if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0) {
656     //    torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
657     control->core()->download_store()->save_resume(download);
658   }
659 
660   // Send the completed request before resuming so we don't reset the
661   // up/downloaded baseline.
662   download->download()->send_completed();
663 
664   // Save the hash in case the finished event erases it.
665   torrent::HashString infohash = download->info()->hash();
666 
667   DL_TRIGGER_EVENT(download, "event.download.finished");
668 
669   if (find(infohash) == end())
670     return;
671 
672 //   if (download->resume_flags() != ~uint32_t())
673 //     throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
674 
675   // See #1292.
676   //
677   // Just reset the value for the moment. If a torrent finishes while
678   // others are hashing, or some other situtation that causes resume
679   // flag to change could cause the state to be invalid.
680   //
681   // TODO: Add a check when setting the flags to see if the torrent is
682   // being hashed.
683   download->set_resume_flags(~uint32_t());
684 
685   if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
686     resume(download,
687            torrent::Download::start_no_create |
688            torrent::Download::start_skip_tracker |
689            torrent::Download::start_keep_baseline);
690 }
691 
692 void
process_meta_download(Download * download)693 DownloadList::process_meta_download(Download* download) {
694   lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Processing meta download.");
695 
696   rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
697   rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
698 
699   std::string metafile = (*download->file_list()->begin())->frozen_path();
700   std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary);
701   if (!file.is_open()) {
702     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not read download metadata.");
703     return;
704   }
705 
706   torrent::Object* bencode = new torrent::Object(torrent::Object::create_map());
707   file >> bencode->insert_key("info", torrent::Object());
708   if (file.fail()) {
709     delete bencode;
710     lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
711     return;
712   }
713   file.close();
714 
715   // Steal the keys we still need. The old download has no use for them.
716   bencode->insert_key("rtorrent_meta_download", torrent::Object()).swap(download->bencode()->get_key("rtorrent_meta_download"));
717   if (download->bencode()->has_key("announce"))
718     bencode->insert_key("announce", torrent::Object()).swap(download->bencode()->get_key("announce"));
719   if (download->bencode()->has_key("announce-list"))
720     bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list"));
721 
722   erase_ptr(download);
723   control->core()->try_create_download_from_meta_download(bencode, metafile);
724 }
725 
726 }
727