LCOV - code coverage report
Current view: top level - snbmodules/src/common - transfer_interface_bittorrent.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 470 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 34 0

            Line data    Source code
       1              : /**
       2              :  * @file transfer_interface_bittorrent.cpp TransferInterfaceRClone protocol class for a Bittorrent transfer
       3              :  *
       4              :  * This is part of the DUNE DAQ , copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : 
       9              : #include "snbmodules/interfaces/transfer_interface_bittorrent.hpp"
      10              : 
      11              : #include <string>
      12              : #include <utility>
      13              : #include <vector>
      14              : 
      15              : namespace dunedaq::snbmodules {
      16              : 
      17              : // return the name of a torrent status enum
      18              : char const*
      19            0 : TransferInterfaceBittorrent::state(lt::torrent_status::state_t s)
      20              : {
      21            0 :   switch (s) {
      22              :     case lt::torrent_status::checking_files:
      23              :       return "checking";
      24            0 :     case lt::torrent_status::downloading_metadata:
      25            0 :       return "dl metadata";
      26            0 :     case lt::torrent_status::downloading:
      27            0 :       return "downloading";
      28            0 :     case lt::torrent_status::finished:
      29            0 :       return "finished";
      30            0 :     case lt::torrent_status::seeding:
      31            0 :       return "seeding";
      32            0 :     case lt::torrent_status::checking_resume_data:
      33            0 :       return "checking resume";
      34            0 :     default:
      35            0 :       return "<>";
      36              :   }
      37              : }
      38              : 
      39            0 : TransferInterfaceBittorrent::TransferInterfaceBittorrent(GroupMetadata& config,
      40              :                                                          bool is_client,
      41              :                                                          std::filesystem::path work_dir,
      42            0 :                                                          const IPFormat& listening_ip)
      43              :   : TransferInterfaceAbstract(config)
      44            0 :   , ses(set_settings(listening_ip, config.get_protocol_options()["port"].get<std::string>()))
      45            0 :   , m_is_client(is_client)
      46            0 :   , m_listening_ip(listening_ip)
      47            0 :   , m_thread([&](std::atomic<bool>& running) { this->do_work(running); })
      48              : {
      49            0 :   m_work_dir = std::move(work_dir);
      50            0 :   m_thread.start_working_thread();
      51              : 
      52            0 :   if (config.get_protocol_options().contains("rate_limit")) {
      53            0 :     m_rate_limit = config.get_protocol_options()["rate_limit"].get<int>();
      54              :   }
      55            0 : }
      56              : 
      57            0 : TransferInterfaceBittorrent::~TransferInterfaceBittorrent()
      58              : {
      59            0 :   m_thread.stop_working_thread();
      60            0 : }
      61              : 
      62              : void
      63            0 : TransferInterfaceBittorrent::do_work(std::atomic<bool>& running_flag)
      64              : try {
      65            0 :   bool m_done = false;
      66            0 :   int finished_torrents = 0;
      67              :   // lt::torrent_handle h;
      68              : 
      69            0 :   FILE* log_file = std::fopen(get_work_dir().append("bittorrent.log").c_str(), "w+");
      70              : 
      71            0 :   TLOG() << "debug : Starting bittorent work on " << m_listening_ip.get_ip_port();
      72              : 
      73            0 :   while (running_flag.load() || save_on_exit) {
      74              : 
      75              :     // Save before exit
      76            0 :     if (save_on_exit && !running_flag.load()) {
      77            0 :       auto const handles = ses.get_torrents();
      78            0 :       for (const auto& h : handles) {
      79            0 :         h.save_resume_data(lt::torrent_handle::only_if_modified | lt::torrent_handle::save_info_dict);
      80              :       }
      81            0 :       m_done = true;
      82            0 :       goto done;
      83            0 :     }
      84              : 
      85            0 :     std::vector<lt::alert*> alerts;
      86            0 :     ses.pop_alerts(&alerts);
      87              : 
      88            0 :     for (lt::alert const* a : alerts) {
      89            0 :       static auto const first_ts = a->timestamp();
      90              : 
      91            0 :       if (log_file) {
      92            0 :         std::fprintf(
      93              :           log_file,
      94              :           "[%ld] %s\n",
      95            0 :           static_cast<std::int64_t>(duration_cast<std::chrono::milliseconds>(a->timestamp() - first_ts).count()),
      96            0 :           a->message().c_str());
      97              :       }
      98              : 
      99            0 :       if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
     100              :         // h = at->handle;
     101            0 :         m_torrent_num++;
     102            0 :         TLOG() << "debug : Added torrent " << at->torrent_name();
     103              :       }
     104              : 
     105            0 :       if (auto p = lt::alert_cast<lt::torrent_removed_alert>(a)) {
     106            0 :         lt::torrent_handle h = p->handle;
     107            0 :       }
     108              : 
     109            0 :       if (auto p = lt::alert_cast<lt::torrent_paused_alert>(a)) {
     110            0 :         lt::torrent_handle h = p->handle;
     111            0 :         h.save_resume_data(lt::torrent_handle::save_info_dict);
     112            0 :       }
     113              : 
     114            0 :       if (auto* p = lt::alert_cast<lt::tracker_list_alert>(a)) {
     115            0 :         (void)p;
     116              :         // if (h == p->handle)
     117              :         // {
     118              :         //     session_state.trackers = std::move(p->trackers);
     119              :         // }
     120              :       }
     121              : 
     122              :       // if (auto *p = lt::alert_cast<lt::file_progress_alert>(a))
     123              :       // {
     124              :       //     m_filename_to_metadata[h.torrent_file()->name()]->set_bytes_transferred(h.status().total_payload_download);
     125              :       //     TLOG() << "debug : Progress: " << h.status().total_payload_download;
     126              :       // }
     127              : 
     128              :       // if we receive the finished alert or an error, we're done
     129            0 :       if (auto p = lt::alert_cast<lt::torrent_finished_alert>(a)) {
     130            0 :         TLOG() << "debug : Torrent finished " << p->torrent_name();
     131            0 :         finished_torrents++;
     132              : 
     133            0 :         p->handle.save_resume_data(lt::torrent_handle::only_if_modified | lt::torrent_handle::save_info_dict);
     134              : 
     135            0 :         m_filename_to_metadata[p->torrent_name()]->set_status(status_type::e_status::FINISHED);
     136            0 :         m_filename_to_metadata[p->torrent_name()]->set_bytes_transferred(
     137            0 :           m_filename_to_metadata[p->torrent_name()]->get_size());
     138              : 
     139            0 :         if (finished_torrents == m_torrent_num && m_is_client) {
     140            0 :           m_done = true;
     141              :         }
     142              :       }
     143            0 :       if (auto p = lt::alert_cast<lt::torrent_error_alert>(a)) {
     144            0 :         ers::error(BittorrentError(ERS_HERE, p->error.message()));
     145              : 
     146            0 :         finished_torrents++;
     147            0 :         if (finished_torrents == m_torrent_num && m_is_client) {
     148            0 :           m_done = true;
     149              :         }
     150              : 
     151            0 :         p->handle.save_resume_data(lt::torrent_handle::only_if_modified | lt::torrent_handle::save_info_dict);
     152              :       }
     153              : 
     154              :       // when resume data is ready, save it
     155            0 :       if (const auto* rd = lt::alert_cast<lt::save_resume_data_alert>(a)) {
     156            0 :         std::ofstream of(get_work_dir().append(".resume_file_" + rd->params.name), std::ios_base::binary);
     157            0 :         of.unsetf(std::ios_base::skipws);
     158            0 :         auto const b = write_resume_data_buf(rd->params);
     159            0 :         of.write(b.data(), static_cast<int>(b.size()));
     160            0 :         if (m_done) {
     161            0 :           goto done;
     162              :         }
     163            0 :       }
     164              : 
     165            0 :       if (auto e = lt::alert_cast<lt::save_resume_data_failed_alert>(a)) {
     166            0 :         ers::warning(BittorrentSaveResumeFileError(ERS_HERE, e->message()));
     167            0 :         if (m_done) {
     168            0 :           goto done;
     169              :         }
     170              :       }
     171              : 
     172            0 :       if (lt::alert_cast<lt::peer_connect_alert>(a)) {
     173            0 :         m_peer_num++;
     174            0 :         m_done = false;
     175              :       }
     176              : 
     177            0 :       if (auto e = lt::alert_cast<lt::peer_error_alert>(a)) {
     178            0 :         m_peer_num--;
     179              :         // std::this_thread::sleep_for(std::chrono::seconds(1));
     180              :         // Try to reconnect
     181              :         // lt::error_code ec;
     182              :         // h.connect_peer(lt::tcp::endpoint(boost::asio::ip::make_address(config->get_source_ip().get_ip(), ec),
     183              :         // std::uint16_t(config->get_source_ip().get_port())));
     184            0 :         ers::warning(BittorrentPeerDisconnectedError(ERS_HERE, e->message()));
     185              :         // f_meta.set_error_code("peer error: " + a->message());
     186              : 
     187            0 :         if (m_peer_num == 0 && m_paused == 0 && !m_is_client) {
     188            0 :           m_done = true;
     189              :         }
     190              :       }
     191              : 
     192            0 :       if (auto e = lt::alert_cast<lt::peer_disconnected_alert>(a)) {
     193            0 :         m_peer_num--;
     194              :         // wait
     195              :         // std::this_thread::sleep_for(std::chrono::seconds(1));
     196              :         // Try to reconnect
     197              :         // lt::error_code ec;
     198              :         // h.connect_peer(lt::tcp::endpoint(boost::asio::ip::make_address(config->get_source_ip().get_ip(), ec),
     199              :         // std::uint16_t(config->get_source_ip().get_port())));
     200            0 :         ers::warning(BittorrentPeerDisconnectedError(ERS_HERE, e->message()));
     201            0 :         if (m_peer_num <= 0 && m_paused == 0 && !m_is_client) {
     202            0 :           m_done = true;
     203              :         }
     204              :       }
     205              : 
     206            0 :       if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
     207              :         // TLOG() << "debug : State update alert";
     208            0 :         if (st->status.empty()) {
     209            0 :           continue;
     210              :         }
     211              : 
     212            0 :         for (uint64_t i = 0; i < st->status.size(); i++) {
     213            0 :           lt::torrent_status const& s = st->status[i];
     214              : 
     215            0 :           if (m_filename_to_metadata[s.name]->get_status() != status_type::e_status::PAUSED) {
     216              : 
     217            0 :             switch (s.state) {
     218            0 :               case lt::torrent_status::checking_files:
     219            0 :                 m_filename_to_metadata[s.name]->set_status(status_type::e_status::CHECKING);
     220              :                 break;
     221            0 :               case lt::torrent_status::downloading_metadata:
     222            0 :                 m_filename_to_metadata[s.name]->set_status(status_type::e_status::PREPARING);
     223              :                 break;
     224            0 :               case lt::torrent_status::downloading:
     225            0 :                 m_filename_to_metadata[s.name]->set_status(status_type::e_status::DOWNLOADING);
     226              :                 break;
     227            0 :               case lt::torrent_status::finished:
     228            0 :                 m_filename_to_metadata[s.name]->set_status(status_type::e_status::FINISHED);
     229              :                 break;
     230            0 :               case lt::torrent_status::seeding:
     231            0 :                 if (m_is_client) {
     232            0 :                   m_filename_to_metadata[s.name]->set_status(status_type::e_status::FINISHED);
     233              :                 } else {
     234            0 :                   m_filename_to_metadata[s.name]->set_status(status_type::e_status::UPLOADING);
     235              :                 }
     236              :                 break;
     237            0 :               case lt::torrent_status::checking_resume_data:
     238            0 :                 m_filename_to_metadata[s.name]->set_status(status_type::e_status::CHECKING);
     239              :                 break;
     240              :               default:
     241              :                 break;
     242              :             }
     243              : 
     244              :             // if (s.num_peers == 0)
     245              :             // {
     246              :             //     m_filename_to_metadata[s.name].set_status(status_type::e_status::WAITING);
     247              :             // }
     248              :           }
     249              : 
     250            0 :           m_filename_to_metadata[s.name]->set_bytes_transferred(s.total_done);
     251              : 
     252            0 :           TLOG() << "is_client " << m_is_client << " [" << i << "]" << s.name << " " << state(s.state) << ' '
     253            0 :                  << (s.download_payload_rate / 1000) << " kB/s " << (s.total_done / 1000) << " kB ("
     254            0 :                  << (s.progress_ppm / 10000) << "%) " << s.current_tracker << " "
     255            0 :                  << static_cast<std::int64_t>(duration_cast<seconds>(s.next_announce).count()) << "s (" << s.num_peers
     256            0 :                  << " peers) " << "\n";
     257              : 
     258              :           // h.post_trackers();
     259              : 
     260              :           // for (lt::announce_entry const &ae : session_state.trackers)
     261              :           // {
     262              :           //     std::cout << ae.url << " ";
     263              :           //     if (ae.verified)
     264              :           //     {
     265              :           //         std::cout << "OK ";
     266              :           //     }
     267              :           //     else
     268              :           //     {
     269              :           //         std::cout << "-- ";
     270              :           //     }
     271              :           //     std::cout << ae.tier << "\n";
     272              :           // }
     273              :           // auto &peers = client_state.peers;
     274              :           // if (print_peers && !peers.empty())
     275              :           // {
     276              :           //     using lt::peer_info;
     277              :           //     // sort connecting towards the bottom of the list, and by peer_id
     278              :           //     // otherwise, to keep the list as stable as possible
     279              :           //     std::sort(peers.begin(), peers.end(), [](peer_info const &lhs, peer_info const &rhs)
     280              :           //               {
     281              :           //         {
     282              :           //             bool const l = bool(lhs.flags & peer_info::connecting);
     283              :           //             bool const r = bool(rhs.flags & peer_info::connecting);
     284              :           //             if (l != r) return l < r;
     285              :           //         }
     286              : 
     287              :           //         {
     288              :           //             bool const l = bool(lhs.flags & peer_info::handshake);
     289              :           //             bool const r = bool(rhs.flags & peer_info::handshake);
     290              :           //             if (l != r) return l < r;
     291              :           //         }
     292              : 
     293              :           //         return lhs.pid < rhs.pid; });
     294              : 
     295              :           //     print_peer_info(out, peers, 10);
     296              :           //     if (print_peers_legend)
     297              :           //     {
     298              :           //         print_peer_legend(out, 10);
     299              :           //     }
     300              :           // }
     301              : 
     302              :           // if (print_trackers)
     303              :           // {
     304              :           //     snprintf(str, sizeof(str), "next_announce: %4" PRId64 " | current tracker: %s\x1b[K\n",
     305              :           //     std::int64_t(duration_cast<seconds>(s.next_announce).count()), s.current_tracker.c_str()); out += str;
     306              :           //     pos += 1;
     307              :           //     h.post_trackers();
     308              :           //     for (lt::announce_entry const &ae : client_state.trackers)
     309              :           //     {
     310              :           //         std::snprintf(str, sizeof(str), "%2d %-55s %s\x1b[K\n", ae.tier, ae.url.c_str(), ae.verified ? "OK
     311              :           //         " : "-  "); out += str; pos += 1; int idx = 0; for (auto const &ep : ae.endpoints)
     312              :           //         {
     313              :           //             ++idx;
     314              :           //             if (pos + 1 >= terminal_height)
     315              :           //             {
     316              :           //                 break;
     317              :           //             }
     318              :           //             if (!ep.enabled)
     319              :           //             {
     320              :           //                 continue;
     321              :           //             }
     322              :           //             for (lt::protocol_version const v : {lt::protocol_version::V1, lt::protocol_version::V2})
     323              :           //             {
     324              :           //                 if (!s.info_hashes.has(v))
     325              :           //                 {
     326              :           //                     continue;
     327              :           //                 }
     328              :           //                 auto const &av = ep.info_hashes[v];
     329              : 
     330              :           //                 std::snprintf(str, sizeof(str), "  [%2d] %s fails: %-3d (%-3d) %s %5d \"%s\" %s\x1b[K\n",
     331              :           //                 idx, v == lt::protocol_version::V1 ? "v1" : "v2", av.fails, ae.fail_limit,
     332              :           //                 to_string(int(total_seconds(av.next_announce - now)), 8).c_str(), av.min_announce > now ?
     333              :           //                 int(total_seconds(av.min_announce - now)) : 0, av.last_error ?
     334              :           //                 av.last_error.message().c_str() : "", av.message.c_str()); out += str; pos += 1;
     335              :           //                 // we only need to show this error once, not for every
     336              :           //                 // endpoint
     337              :           //                 if (av.last_error == boost::asio::error::host_not_found)
     338              :           //                 {
     339              :           //                     goto tracker_done;
     340              :           //                 }
     341              :           //             }
     342              :           //         }
     343              :           //     tracker_done:
     344              : 
     345              :           //         if (pos + 1 >= terminal_height)
     346              :           //         {
     347              :           //             break;
     348              :           //         }
     349              :           //     }
     350              :           // }
     351              :         }
     352              :         // std::cout << "\x1b[K";
     353              :         // std::cout.flush();
     354              :       }
     355              :     }
     356            0 :     std::this_thread::sleep_for(std::chrono::milliseconds(200));
     357              : 
     358              :     // ask the session to post a state_update_alert, to update our
     359              :     // state output for the torrent
     360            0 :     ses.post_torrent_updates();
     361            0 :     ses.post_session_stats();
     362              : 
     363              :     // save resume data once every 30 seconds
     364              :     // if (clk::now() - last_save_resume > std::chrono::seconds(30))
     365              :     // {
     366              :     //     h.save_resume_data(lt::torrent_handle::only_if_modified | lt::torrent_handle::save_info_dict);
     367              :     //     last_save_resume = clk::now();
     368              :     // }
     369            0 :   }
     370            0 : done:
     371              : 
     372            0 :   for (auto& [k, s] : m_filename_to_metadata) {
     373            0 :     if (!m_is_client) {
     374            0 :       s->set_status(status_type::e_status::FINISHED);
     375              :       // deleting torrents files
     376            0 :       std::filesystem::remove(get_work_dir().append(k + ".torrent"));
     377            0 :     } else if (s->get_status() != status_type::e_status::FINISHED) {
     378            0 :       s->set_status(status_type::e_status::ERROR);
     379            0 :       s->set_error_code("Transfer interrupted");
     380              :     }
     381              :   }
     382              : 
     383            0 :   TLOG() << "\nBittorent session done, shutting down";
     384            0 :   if (log_file) {
     385            0 :     std::fclose(log_file);
     386              :   }
     387              :   return;
     388            0 : } catch (std::exception& e) {
     389              :   // TODO: handle error
     390            0 :   std::cerr << "Error: " << e.what() << std::endl;
     391            0 : }
     392              : 
     393              : bool
     394            0 : TransferInterfaceBittorrent::add_magnet(lt::string_view uri, const std::filesystem::path& dest)
     395              : try {
     396            0 :   TLOG() << "debug : loading parameters from magnet " << uri.to_string();
     397            0 :   lt::error_code ec;
     398            0 :   lt::add_torrent_params p = lt::parse_magnet_uri(uri.to_string(), ec);
     399              : 
     400            0 :   if (ec) {
     401            0 :     ers::error(BittorrentInvalidMagnetLinkError(ERS_HERE, uri.to_string()));
     402            0 :     return false;
     403              :   }
     404              : 
     405              :   // std::vector<char> resume_data;
     406              :   // if (load_file(resume_file(p.info_hashes, session_number), resume_data))
     407              :   // {
     408              :   //     p = lt::read_resume_data(resume_data, ec);
     409              :   //     if (ec)
     410              :   //     {
     411              :   //         std::printf("  failed to load resume data: %s\n", ec.message().c_str());
     412              :   //     }
     413              :   // }
     414              : 
     415            0 :   set_torrent_params(p, dest);
     416              : 
     417            0 :   TLOG() << "debug : adding torrent";
     418            0 :   ses.async_add_torrent(std::move(p));
     419              :   return true;
     420            0 : } catch (lt::system_error const& e) {
     421            0 :   ers::error(BittorrentInvalidMagnetLinkError(ERS_HERE, e.code().message()));
     422            0 :   return false;
     423            0 : }
     424              : 
     425              : // return magnet url
     426              : std::string
     427            0 : TransferInterfaceBittorrent::add_torrent(const std::string& torrent, const std::filesystem::path& dest)
     428              : try {
     429            0 :   using lt::storage_mode_t;
     430              : 
     431            0 :   TLOG() << "debug : [" << m_torrent_num << "] " << torrent;
     432              : 
     433              :   // lt::error_code ec;
     434            0 :   lt::add_torrent_params p = lt::load_torrent_file(torrent);
     435              : 
     436              :   // std::vector<char> resume_data;
     437              :   // if (load_file(resume_file(atp.info_hashes, session_number), resume_data))
     438              :   // {
     439              :   //     lt::add_torrent_params rd = lt::read_resume_data(resume_data, ec);
     440              :   //     if (ec)
     441              :   //     {
     442              :   //         std::printf("  failed to load resume data: %s\n", ec.message().c_str());
     443              :   //     }
     444              :   //     else
     445              :   //     {
     446              :   //         atp = rd;
     447              :   //     }
     448              :   // }
     449              : 
     450            0 :   set_torrent_params(p, dest);
     451            0 :   std::string magnet = lt::make_magnet_uri(p);
     452              : 
     453            0 :   ses.async_add_torrent(std::move(p));
     454              : 
     455            0 :   return magnet;
     456            0 : } catch (lt::system_error const& e) {
     457            0 :   ers::error(BittorrentInvalidTorrentFileError(ERS_HERE, e.code().message()));
     458            0 :   return "";
     459            0 : }
     460              : 
     461              : void
     462            0 : TransferInterfaceBittorrent::set_torrent_params(lt::add_torrent_params& p, const std::filesystem::path& dest)
     463              : {
     464            0 :   TLOG() << "debug : setting torrent parameters";
     465              : 
     466            0 :   bool seed_mode = !m_is_client;
     467            0 :   bool super_seeding = false;
     468            0 :   bool upload_mode = !m_is_client;
     469              : 
     470            0 :   bool sequential_mode = true;
     471            0 :   int max_connections_per_torrent = 100;
     472            0 :   std::string save_path = dest;
     473              :   // limits in bytes per seconds hqndle by session ?
     474            0 :   int torrent_upload_limit = -1;
     475            0 :   int torrent_download_limit = m_rate_limit;
     476              : 
     477            0 :   p.max_connections = max_connections_per_torrent;
     478            0 :   p.max_uploads = -1;
     479            0 :   p.upload_limit = torrent_upload_limit;
     480            0 :   p.download_limit = torrent_download_limit;
     481              :   // atp.flags &= ~lt::torrent_flags::duplicate_is_error;
     482              : 
     483              :   // not auto managed
     484            0 :   p.flags &= ~lt::torrent_flags::paused;
     485            0 :   p.flags &= ~lt::torrent_flags::auto_managed;
     486              : 
     487            0 :   if (super_seeding) {
     488              :     p.flags |= lt::torrent_flags::super_seeding;
     489              :   } else {
     490            0 :     p.flags &= ~lt::torrent_flags::super_seeding;
     491              :   }
     492              : 
     493            0 :   if (seed_mode) {
     494            0 :     p.flags |= lt::torrent_flags::seed_mode;
     495              :   } else {
     496            0 :     p.flags &= ~lt::torrent_flags::seed_mode;
     497              :   }
     498              : 
     499            0 :   if (upload_mode) {
     500            0 :     p.flags |= lt::torrent_flags::upload_mode;
     501              :   } else {
     502            0 :     p.flags &= ~lt::torrent_flags::upload_mode;
     503              :   }
     504              : 
     505            0 :   if (sequential_mode) {
     506            0 :     p.flags |= lt::torrent_flags::sequential_download;
     507              :   } else {
     508              :     p.flags &= ~lt::torrent_flags::sequential_download;
     509              :   }
     510              : 
     511            0 :   p.save_path = save_path;
     512            0 :   p.storage_mode = lt::storage_mode_allocate;
     513            0 : }
     514              : 
     515              : lt::session_params
     516            0 : TransferInterfaceBittorrent::set_settings(const IPFormat& listen_interface, const std::string& listen_port)
     517              : {
     518            0 :   lt::session_params sp;
     519            0 :   auto& p = sp.settings;
     520              : 
     521            0 :   sp.disk_io_constructor = lt::default_disk_io_constructor;
     522              : 
     523            0 :   int block_size = 1024 * 1024;
     524            0 :   std::string outgoing_interface = listen_interface.get_ip();
     525            0 :   std::string listen_interfaces = listen_interface.get_ip() + ":" + listen_port;
     526              : 
     527            0 :   p.set_bool(lt::settings_pack::enable_dht, false);
     528            0 :   p.set_int(lt::settings_pack::auto_manage_interval, 60);
     529            0 :   p.set_int(lt::settings_pack::auto_manage_startup, 1);
     530            0 :   p.set_int(lt::settings_pack::min_reconnect_time, 1);
     531            0 :   p.set_int(lt::settings_pack::max_failcount, 10);
     532              : 
     533              :   // p.set_str(lt::settings_pack::dht_bootstrap_nodes, "192.168.0.105:5001,192.168.0.106:5002");
     534              :   // p.set_bool(lt::settings_pack::use_dht_as_fallback, false);
     535              :   // p.set_bool(lt::settings_pack::dht_prefer_verified_node_ids, false);
     536              :   // p.set_bool(lt::settings_pack::dht_restrict_routing_ips, false);
     537              :   // p.set_bool(lt::settings_pack::dht_restrict_search_ips, false);
     538              : 
     539            0 :   p.set_str(lt::settings_pack::outgoing_interfaces, outgoing_interface);
     540            0 :   p.set_bool(lt::settings_pack::strict_end_game_mode, false);
     541              :   // p.set_bool(lt::settings_pack::low_prio_disk, false);
     542            0 :   p.set_bool(lt::settings_pack::smooth_connects, false);
     543            0 :   p.set_bool(lt::settings_pack::allow_multiple_connections_per_ip, true);
     544            0 :   p.set_bool(lt::settings_pack::announce_to_all_tiers, true);
     545            0 :   p.set_bool(lt::settings_pack::announce_to_all_trackers, true);
     546            0 :   p.set_bool(lt::settings_pack::auto_sequential, true);
     547              :   // p.set_bool(lt::settings_pack::coalesce_reads, true);
     548              :   // p.set_bool(lt::settings_pack::coalesce_writes, true);
     549              :   // p.set_bool(lt::settings_pack::contiguous_recv_buffer, true);
     550            0 :   p.set_bool(lt::settings_pack::incoming_starts_queued_torrents, true);
     551              : 
     552            0 :   p.set_bool(lt::settings_pack::enable_incoming_tcp, true);
     553            0 :   p.set_bool(lt::settings_pack::enable_outgoing_tcp, true);
     554            0 :   p.set_bool(lt::settings_pack::enable_incoming_utp, false);
     555            0 :   p.set_bool(lt::settings_pack::enable_outgoing_utp, false);
     556            0 :   p.set_bool(lt::settings_pack::enable_lsd, false);
     557            0 :   p.set_bool(lt::settings_pack::enable_natpmp, false);
     558            0 :   p.set_bool(lt::settings_pack::enable_upnp, false);
     559            0 :   p.set_bool(lt::settings_pack::prefer_rc4, false);
     560            0 :   p.set_bool(lt::settings_pack::prefer_udp_trackers, true);
     561            0 :   p.set_bool(lt::settings_pack::rate_limit_ip_overhead, false);
     562              :   // p.set_bool(lt::settings_pack::rate_limit_utp, false);
     563              : 
     564            0 :   p.set_int(lt::settings_pack::aio_threads, 1);
     565              :   // p.set_int(lt::settings_pack::network_threads, 1);
     566            0 :   p.set_int(lt::settings_pack::hashing_threads, 1);
     567            0 :   p.set_int(lt::settings_pack::disk_io_read_mode, 3);
     568            0 :   p.set_int(lt::settings_pack::disk_io_write_mode, 3);
     569            0 :   p.set_int(lt::settings_pack::allowed_enc_level, 3);
     570            0 :   p.set_int(lt::settings_pack::allowed_fast_set_size, 5);
     571            0 :   p.set_int(lt::settings_pack::seed_choking_algorithm, 1);
     572            0 :   p.set_int(lt::settings_pack::choking_algorithm, 0);
     573            0 :   p.set_int(lt::settings_pack::in_enc_policy, 2);
     574            0 :   p.set_int(lt::settings_pack::out_enc_policy, 2);
     575            0 :   p.set_int(lt::settings_pack::mixed_mode_algorithm, 0);
     576            0 :   p.set_int(lt::settings_pack::suggest_mode, 0);
     577              : 
     578            0 :   p.set_int(lt::settings_pack::close_file_interval, 0);
     579            0 :   p.set_int(lt::settings_pack::inactivity_timeout, 10);
     580            0 :   p.set_int(lt::settings_pack::request_queue_time, 50);
     581            0 :   p.set_int(lt::settings_pack::peer_timeout, 20);
     582            0 :   p.set_int(lt::settings_pack::request_timeout, 10);
     583            0 :   p.set_int(lt::settings_pack::predictive_piece_announce, 20);
     584            0 :   p.set_int(lt::settings_pack::whole_pieces_threshold, 20);
     585            0 :   p.set_int(lt::settings_pack::mmap_file_size_cutoff, 0);
     586              : 
     587              :   // limits in bytes per seconds
     588            0 :   p.set_int(lt::settings_pack::upload_rate_limit, 0);
     589            0 :   p.set_int(lt::settings_pack::download_rate_limit, 0);
     590              :   // p.set_int(lt::settings_pack::local_download_rate_limit, 0);
     591              :   // p.set_int(lt::settings_pack::local_upload_rate_limit, 0);
     592            0 :   p.set_int(lt::settings_pack::unchoke_slots_limit, -1);
     593            0 :   p.set_int(lt::settings_pack::max_failcount, 3);
     594            0 :   p.set_int(lt::settings_pack::max_http_recv_buffer_size, 1024 * 1024 * 8);
     595            0 :   p.set_int(lt::settings_pack::max_rejects, 20);
     596            0 :   p.set_int(lt::settings_pack::max_queued_disk_bytes, 1024 * 1024 * 1024);
     597              : 
     598            0 :   p.set_int(lt::settings_pack::read_cache_line_size, 512);
     599              :   // p.set_int(lt::settings_pack::cache_buffer_chunk_size, 512);
     600              :   // p.set_int(lt::settings_pack::cache_expiry, 400);
     601            0 :   p.set_int(lt::settings_pack::cache_size_volatile, 128);
     602            0 :   p.set_int(lt::settings_pack::checking_mem_usage, 1024);
     603              :   // p.set_bool(lt::settings_pack::use_read_cache, true);
     604              :   // p.set_bool(lt::settings_pack::use_write_cache, true);
     605              :   // p.set_bool(lt::settings_pack::use_disk_read_ahead, true);
     606            0 :   p.set_bool(lt::settings_pack::use_parole_mode, false);
     607              :   // p.set_bool(lt::settings_pack::guided_read_cache, true);
     608              :   // p.set_bool(lt::settings_pack::volatile_read_cache, false);
     609            0 :   p.set_int(lt::settings_pack::tracker_completion_timeout, 30);
     610            0 :   p.set_int(lt::settings_pack::tracker_receive_timeout, 30);
     611            0 :   p.set_int(lt::settings_pack::stop_tracker_timeout, 30);
     612            0 :   p.set_int(lt::settings_pack::tracker_backoff, 250);
     613            0 :   p.set_int(lt::settings_pack::tracker_maximum_response_length, 1024 * 1024 * 8);
     614            0 :   p.set_bool(lt::settings_pack::validate_https_trackers, false);
     615            0 :   p.set_int(lt::settings_pack::alert_mask, lt::alert_category::all);
     616              : 
     617            0 :   p.set_str(lt::settings_pack::listen_interfaces, listen_interfaces);
     618              : 
     619            0 :   if (m_is_client) {
     620              :     // p.set_str(lt::settings_pack::user_agent, "DuneTorrentClient");
     621            0 :     p.set_bool(lt::settings_pack::piece_extent_affinity, true);
     622            0 :     p.set_bool(lt::settings_pack::seeding_outgoing_connections, false);
     623              : 
     624            0 :     p.set_int(lt::settings_pack::tick_interval, 500);
     625            0 :     p.set_int(lt::settings_pack::torrent_connect_boost, 255);
     626              : 
     627            0 :     p.set_int(lt::settings_pack::connection_speed, 0);
     628            0 :     p.set_int(lt::settings_pack::active_seeds, 0);
     629            0 :     p.set_int(lt::settings_pack::active_downloads, 10);
     630            0 :     p.set_int(lt::settings_pack::active_checking, 10);
     631            0 :     p.set_int(lt::settings_pack::active_limit, 10);
     632            0 :     p.set_int(lt::settings_pack::active_tracker_limit, 10);
     633            0 :     p.set_int(lt::settings_pack::connections_limit, 10);
     634              :     // p.set_int(lt::settings_pack::half_open_limit, 500);
     635            0 :     p.set_int(lt::settings_pack::file_pool_size, 10);
     636            0 :     p.set_int(lt::settings_pack::listen_queue_size, 10);
     637            0 :     p.set_int(lt::settings_pack::max_allowed_in_request_queue, 50000);
     638            0 :     p.set_int(lt::settings_pack::max_out_request_queue, 50000);
     639            0 :     p.set_int(lt::settings_pack::dht_upload_rate_limit, block_size * 10);
     640              : 
     641            0 :     p.set_int(lt::settings_pack::write_cache_line_size, 512);
     642              :     // p.set_int(lt::settings_pack::cache_size, 1024 * 1);
     643              :     // p.set_bool(lt::settings_pack::use_disk_cache_pool, true);
     644              :     // p.set_bool(lt::settings_pack::allow_partial_disk_writes, false);
     645              : 
     646            0 :     p.set_int(lt::settings_pack::send_buffer_watermark_factor, 50);
     647            0 :     p.set_int(lt::settings_pack::send_buffer_low_watermark, 1024 * 10);
     648            0 :     p.set_int(lt::settings_pack::send_buffer_watermark, 1024 * 500);
     649            0 :     p.set_int(lt::settings_pack::send_socket_buffer_size, 1024 * 512);
     650            0 :     p.set_int(lt::settings_pack::recv_socket_buffer_size, 1024 * 1024 * 1024);
     651              : 
     652            0 :     p.set_bool(lt::settings_pack::no_atime_storage, true);
     653            0 :     p.set_bool(lt::settings_pack::enable_set_file_valid_data, false);
     654            0 :     p.set_int(lt::settings_pack::disk_write_mode, 1);
     655            0 :     p.set_bool(lt::settings_pack::disable_hash_checks, false);
     656              :   } else {
     657              : 
     658              :     // p.set_str(lt::settings_pack::user_agent, "DuneTorrentSeeder");
     659            0 :     p.set_bool(lt::settings_pack::piece_extent_affinity, false);
     660            0 :     p.set_bool(lt::settings_pack::seeding_outgoing_connections, true);
     661              : 
     662            0 :     p.set_int(lt::settings_pack::tick_interval, 150);
     663            0 :     p.set_int(lt::settings_pack::torrent_connect_boost, 255);
     664              : 
     665            0 :     p.set_int(lt::settings_pack::connection_speed, 200);
     666            0 :     p.set_int(lt::settings_pack::active_seeds, 1000);
     667            0 :     p.set_int(lt::settings_pack::active_downloads, 0);
     668            0 :     p.set_int(lt::settings_pack::active_checking, 1000);
     669            0 :     p.set_int(lt::settings_pack::active_limit, 2000);
     670            0 :     p.set_int(lt::settings_pack::active_tracker_limit, 2000);
     671            0 :     p.set_int(lt::settings_pack::connections_limit, 8000);
     672              :     // p.set_int(lt::settings_pack::half_open_limit, 50);
     673            0 :     p.set_int(lt::settings_pack::file_pool_size, 20);
     674            0 :     p.set_int(lt::settings_pack::listen_queue_size, 3000);
     675            0 :     p.set_int(lt::settings_pack::max_allowed_in_request_queue, 2000);
     676            0 :     p.set_int(lt::settings_pack::max_out_request_queue, 2000);
     677            0 :     p.set_int(lt::settings_pack::dht_upload_rate_limit, block_size * 8);
     678              : 
     679            0 :     p.set_int(lt::settings_pack::write_cache_line_size, 128);
     680              :     // p.set_int(lt::settings_pack::cache_size, 1024 * 50);
     681              :     // p.set_bool(lt::settings_pack::use_disk_cache_pool, false);
     682              :     // p.set_bool(lt::settings_pack::allow_partial_disk_writes, false);
     683              : 
     684            0 :     p.set_int(lt::settings_pack::send_buffer_watermark_factor, 150);
     685            0 :     p.set_int(lt::settings_pack::send_buffer_low_watermark, 1024 * 10);
     686            0 :     p.set_int(lt::settings_pack::send_buffer_watermark, 1024 * 1024 * 1024);
     687            0 :     p.set_int(lt::settings_pack::send_socket_buffer_size, 1024 * 1024 * 1024);
     688            0 :     p.set_int(lt::settings_pack::recv_socket_buffer_size, 1024 * 512);
     689              : 
     690              :     // p.set_bool(lt::settings_pack::no_atime_storage, true);
     691              :     // p.set_bool(lt::settings_pack::enable_set_file_valid_data, false);
     692              :     // p.set_int(lt::settings_pack::disk_write_mode, 1);
     693              :     // p.set_bool(lt::settings_pack::disable_hash_checks, false);
     694              :   }
     695              : 
     696            0 :   return sp;
     697            0 : }
     698              : 
     699              : std::vector<char>
     700            0 : TransferInterfaceBittorrent::load_file(std::string const& filename)
     701              : {
     702            0 :   std::fstream in;
     703            0 :   in.exceptions(std::ifstream::failbit);
     704            0 :   in.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
     705            0 :   in.seekg(0, std::ios_base::end);
     706            0 :   size_t const size = static_cast<size_t>(in.tellg());
     707            0 :   in.seekg(0, std::ios_base::beg);
     708            0 :   std::vector<char> ret(size);
     709            0 :   in.read(ret.data(), static_cast<int>(ret.size()));
     710            0 :   return ret;
     711            0 : }
     712              : 
     713              : std::string
     714            0 : TransferInterfaceBittorrent::branch_path(std::string const& f)
     715              : {
     716            0 :   if (f.empty()) {
     717            0 :     return f;
     718              :   }
     719              : 
     720            0 :   if (f == "/") {
     721            0 :     return "";
     722              :   }
     723              : 
     724            0 :   auto len = f.size();
     725              :   // if the last character is / or \ ignore it
     726            0 :   if (f[len - 1] == '/' || f[len - 1] == '\\') {
     727              :     --len;
     728              :   }
     729            0 :   while (len > 0) {
     730            0 :     --len;
     731            0 :     if (f[len] == '/' || f[len] == '\\') {
     732              :       break;
     733              :     }
     734              :   }
     735              : 
     736            0 :   if (f[len] == '/' || f[len] == '\\') {
     737            0 :     ++len;
     738              :   }
     739            0 :   return std::string(f.c_str(), len);
     740              : }
     741              : 
     742              : // do not include files and folders whose
     743              : // name starts with a .
     744              : bool
     745            0 : TransferInterfaceBittorrent::file_filter(std::string const& f)
     746              : {
     747            0 :   if (f.empty()) {
     748              :     return false;
     749              :   }
     750              : 
     751            0 :   char const* first = f.c_str();
     752            0 :   char const* sep = strrchr(first, '/');
     753              : 
     754              :   // if there is no parent path, just set 'sep'
     755              :   // to point to the filename.
     756              :   // if there is a parent path, skip the '/' character
     757            0 :   if (sep == nullptr) {
     758              :     sep = first;
     759              :   } else {
     760            0 :     ++sep; // NOLINT
     761              :   }
     762              : 
     763              :   // return false if the first character of the filename is a .
     764            0 :   if (sep[0] == '.') // NOLINT
     765              :   {
     766            0 :     return false;
     767              :   }
     768              : 
     769              :   return true;
     770              : }
     771              : 
     772              : bool
     773            0 : TransferInterfaceBittorrent::make_torrent(std::filesystem::path full_path,
     774              :                                           int piece_size,
     775              :                                           const std::string& tracker,
     776              :                                           const std::string& outfile)
     777              : try {
     778            0 :   std::string creator_str = "libtorrent";
     779            0 :   std::string comment_str;
     780              : 
     781            0 :   std::vector<std::string> web_seeds;
     782            0 :   std::vector<std::string> trackers;
     783            0 :   std::vector<std::string> collections;
     784            0 :   std::vector<lt::sha1_hash> similar;
     785            0 :   lt::create_flags_t flags = {};
     786            0 :   std::string root_cert;
     787              : 
     788            0 :   flags |= lt::create_torrent::v2_only;
     789            0 :   flags |= lt::create_torrent::modification_time;
     790              : 
     791            0 :   lt::file_storage fs;
     792            0 :   if (full_path.is_relative()) {
     793            0 :     full_path = std::filesystem::absolute(full_path);
     794              :   }
     795              : 
     796            0 :   lt::add_files(fs, full_path.string(), file_filter, flags);
     797            0 :   if (fs.num_files() == 0) {
     798            0 :     std::cerr << "no files specified.\n";
     799              :     return true;
     800              :   }
     801              : 
     802            0 :   lt::create_torrent t(fs, piece_size, flags);
     803            0 :   int tier = 0;
     804            0 :   for (std::string const& tr : trackers) {
     805            0 :     if (tr == "-") {
     806            0 :       ++tier;
     807              :     } else {
     808            0 :       t.add_tracker(tr, tier);
     809              :     }
     810              :   }
     811              : 
     812            0 :   t.add_tracker(tracker);
     813            0 :   t.set_priv(false);
     814              : 
     815            0 :   auto const num = t.num_pieces();
     816            0 :   lt::set_piece_hashes(
     817            0 :     t, branch_path(full_path), [num](lt::piece_index_t const p) { std::cerr << "\r" << p << "/" << num; });
     818              : 
     819            0 :   std::cerr << "\n";
     820            0 :   t.set_creator(creator_str.c_str());
     821            0 :   if (!comment_str.empty()) {
     822            0 :     t.set_comment(comment_str.c_str());
     823              :   }
     824              : 
     825              :   // create the torrent and print it to stdout
     826            0 :   std::vector<char> torrent;
     827              : 
     828              :   // Silent the output for the logs
     829              :   // std::cout.setstate(std::ios_base::failbit);
     830            0 :   lt::bencode(back_inserter(torrent), t.generate());
     831              :   // std::cout.clear();
     832              : 
     833            0 :   if (!outfile.empty()) {
     834            0 :     std::fstream out;
     835            0 :     out.exceptions(std::ifstream::failbit);
     836            0 :     out.open(outfile.c_str(), std::ios_base::out | std::ios_base::binary);
     837            0 :     out.write(torrent.data(), static_cast<int>(torrent.size()));
     838            0 :   } else {
     839              :     // TODO Aug-14-2022 Leo Joly leo.vincent.andre.joly@cern.ch : Add error code
     840              :     // std::cout.write(torrent.data(), int(torrent.size()));
     841              :     return false;
     842              :   }
     843              : 
     844            0 :   return true;
     845            0 : } catch (std::exception& e) {
     846            0 :   std::cerr << "ERROR: " << e.what() << "\n";
     847            0 :   return false;
     848            0 : }
     849              : 
     850              : void
     851            0 : TransferInterfaceBittorrent::generate_torrents_files(const std::filesystem::path& dest, const std::string& tracker)
     852              : {
     853            0 :   for (const auto& f_meta : get_transfer_options().get_transfers_meta()) {
     854            0 :     std::filesystem::path tmp = dest;
     855            0 :     make_torrent(f_meta->get_file_path(),
     856            0 :                  static_cast<int>(pow(2, 23)),
     857              :                  tracker,
     858            0 :                  tmp.append(f_meta->get_file_name() + ".torrent").string());
     859            0 :   }
     860            0 : }
     861              : 
     862              : bool
     863            0 : TransferInterfaceBittorrent::upload_file(TransferMetadata& f_meta)
     864              : {
     865            0 :   TLOG() << "debug : uploading " << f_meta.get_file_name();
     866              : 
     867            0 :   if (add_torrent(get_work_dir().append(f_meta.get_file_name() + ".torrent"),
     868            0 :                   f_meta.get_file_path().remove_filename()) == "") {
     869            0 :     f_meta.set_error_code("failed to add torrent to session");
     870            0 :     return false;
     871              :   }
     872              : 
     873            0 :   m_filename_to_metadata[f_meta.get_file_name()] = &f_meta;
     874            0 :   return true;
     875              : }
     876              : 
     877              : bool
     878            0 : TransferInterfaceBittorrent::download_file(TransferMetadata& f_meta, std::filesystem::path dest)
     879              : {
     880            0 :   TLOG() << "debug : starting download " << f_meta.get_file_name();
     881              : 
     882              :   // need to add before adding magnet because can instant access after adding magnet
     883            0 :   m_filename_to_metadata[f_meta.get_file_name()] = &f_meta;
     884              : 
     885            0 :   if (add_magnet(f_meta.get_magnet_link(), dest)) {
     886            0 :     TLOG() << "debug : added magnet passed ";
     887              :   } else {
     888              :     // erasing from map because we failed to add magnet
     889            0 :     m_filename_to_metadata.erase(f_meta.get_file_name());
     890            0 :     f_meta.set_error_code("failed to add magnet link to session");
     891            0 :     return false;
     892              :   }
     893              : 
     894              :   // add_torrent(get_work_dir().append(f_meta.get_file_name() + ".torrent"), get_work_dir().append(".."));
     895            0 :   return true;
     896              : }
     897              : 
     898              : bool
     899            0 : TransferInterfaceBittorrent::pause_file(TransferMetadata& f_meta)
     900              : {
     901            0 :   auto handles = ses.get_torrents();
     902            0 :   for (const auto& h : handles) {
     903            0 :     if (h.torrent_file()->name() == f_meta.get_file_name()) {
     904            0 :       m_paused++;
     905            0 :       h.pause(lt::torrent_handle::graceful_pause);
     906            0 :       TLOG() << "debug : pausing " << f_meta.get_file_name() << " and saving pause data in " << get_work_dir().string()
     907            0 :              << "/.resume_file_" << f_meta.get_file_name();
     908            0 :       break;
     909              :     }
     910              :   }
     911              : 
     912            0 :   return true;
     913            0 : }
     914              : 
     915              : bool
     916            0 : TransferInterfaceBittorrent::resume_file(TransferMetadata& f_meta)
     917              : {
     918              : 
     919            0 :   bool found = false;
     920            0 :   auto const handles = ses.get_torrents();
     921            0 :   for (const auto& h : handles) {
     922            0 :     if (h.torrent_file()->name() == f_meta.get_file_name()) {
     923            0 :       m_paused--;
     924            0 :       h.resume();
     925              :       // lt::error_code ec;
     926              :       // TODO
     927              :       // h.connect_peer(lt::tcp::endpoint(boost::asio::ip::make_address("192.168.0.106", ec), std::uint16_t(5010)));
     928              :       // if (!peer.empty())
     929              :       // {
     930              :       //     auto port = peer.find_last_of(':');
     931              :       //     if (port != std::string::npos)
     932              :       //     {
     933              :       //         peer[port++] = '\0';
     934              :       //         char const* ip = peer.data();
     935              :       //         int const peer_port = atoi(peer.data() + port);
     936              :       //         error_code ec;
     937              :       //         if (peer_port > 0)
     938              :       //         {
     939              :       //             h.connect_peer(tcp::endpoint(asio::ip::make_address(ip, ec), std::uint16_t(peer_port)));
     940              :       //         }
     941              :       //     }
     942              :       // }
     943              :       found = true;
     944              :       break;
     945              :     }
     946              :   }
     947              : 
     948            0 :   if (!found) {
     949              :     // load resume data from disk and pass it in as we add the magnet link
     950            0 :     auto buf = load_file(get_work_dir().append(".resume_file" + f_meta.get_file_name()));
     951            0 :     lt::add_torrent_params atp;
     952              : 
     953            0 :     if (buf.size()) {
     954            0 :       atp = lt::read_resume_data(buf);
     955              :     } else {
     956            0 :       ers::error(BittorrentLoadResumeFileError(ERS_HERE, f_meta.get_file_name()));
     957            0 :       f_meta.set_error_code("failed to load resume data");
     958            0 :       return false;
     959              :     }
     960              : 
     961            0 :     m_filename_to_metadata[f_meta.get_file_name()] = &f_meta;
     962            0 :     ses.async_add_torrent(std::move(atp));
     963            0 :   }
     964              : 
     965              :   return true;
     966            0 : }
     967              : 
     968              : bool
     969            0 : TransferInterfaceBittorrent::cancel_file(TransferMetadata& f_meta)
     970              : {
     971            0 :   auto const handles = ses.get_torrents();
     972            0 :   for (const auto& h : handles) {
     973            0 :     if (h.torrent_file()->name() == f_meta.get_file_name()) {
     974              :       // Remove torrent from session
     975            0 :       ses.remove_torrent(h);
     976            0 :       break;
     977              :     }
     978              :   }
     979              : 
     980              :   // wait for the session to remove the torrent
     981            0 :   std::this_thread::sleep_for(std::chrono::seconds(1));
     982            0 :   m_filename_to_metadata.erase(f_meta.get_file_name());
     983              : 
     984              :   // remove resume data
     985            0 :   std::filesystem::remove(get_work_dir().append(".resume_file" + f_meta.get_file_name()));
     986              : 
     987              :   // remove torrent file if uploader or file if downloader
     988            0 :   if (!m_is_client) {
     989            0 :     std::filesystem::remove(get_work_dir().append(f_meta.get_file_name() + ".torrent"));
     990              :   } else {
     991            0 :     std::filesystem::remove(get_work_dir().append(f_meta.get_file_name()));
     992              :   }
     993              : 
     994            0 :   return true;
     995            0 : }
     996              : 
     997              : // TODO necessary ?
     998              : bool
     999            0 : TransferInterfaceBittorrent::hash_file(TransferMetadata& f_meta)
    1000              : {
    1001            0 :   (void)f_meta;
    1002            0 :   return true;
    1003              : }
    1004              : 
    1005              : // Custom disk IO interface
    1006              : // struct temp_storage
    1007              : // {
    1008              : //     explicit temp_storage(lt::file_storage const &fs) : m_files(fs) {}
    1009              : 
    1010              : //     lt::span<char const> readv(lt::peer_request const r, lt::storage_error &ec) const
    1011              : //     {
    1012              : //         auto const i = m_file_data.find(r.piece);
    1013              : //         if (i == m_file_data.end())
    1014              : //         {
    1015              : //             ec.operation = lt::operation_t::file_read;
    1016              : //             ec.ec = boost::asio::error::eof;
    1017              : //             return {};
    1018              : //         }
    1019              : //         if (int(i->second.size()) <= r.start)
    1020              : //         {
    1021              : //             ec.operation = lt::operation_t::file_read;
    1022              : //             ec.ec = boost::asio::error::eof;
    1023              : //             return {};
    1024              : //         }
    1025              : //         return {i->second.data() + r.start, std::min(r.length, int(i->second.size()) - r.start)};
    1026              : //     }
    1027              : //     void writev(lt::span<char const> const b, lt::piece_index_t const piece, int const offset)
    1028              : //     {
    1029              : //         auto &data = m_file_data[piece];
    1030              : //         if (data.empty())
    1031              : //         {
    1032              : //             // allocate the whole piece, otherwise we'll invalidate the pointers
    1033              : //             // we have returned back to libtorrent
    1034              : //             int const size = piece_size(piece);
    1035              : //             data.resize(std::size_t(size));
    1036              : //         }
    1037              : //         TORRENT_ASSERT(offset + b.size() <= int(data.size()));
    1038              : //         std::memcpy(data.data() + offset, b.data(), std::size_t(b.size()));
    1039              : //     }
    1040              : //     lt::sha1_hash hash(lt::piece_index_t const piece, lt::span<lt::sha256_hash> const block_hashes, lt::storage_error
    1041              : //     &ec) const
    1042              : //     {
    1043              : //         auto const i = m_file_data.find(piece);
    1044              : //         if (i == m_file_data.end())
    1045              : //         {
    1046              : //             ec.operation = lt::operation_t::file_read;
    1047              : //             ec.ec = boost::asio::error::eof;
    1048              : //             return {};
    1049              : //         }
    1050              : //         if (!block_hashes.empty())
    1051              : //         {
    1052              : //             int const piece_size2 = m_files.piece_size2(piece);
    1053              : //             int const blocks_in_piece2 = m_files.blocks_in_piece2(piece);
    1054              : //             char const *buf = i->second.data();
    1055              : //             std::int64_t offset = 0;
    1056              : //             for (int k = 0; k < blocks_in_piece2; ++k)
    1057              : //             {
    1058              : //                 lt::hasher256 h2;
    1059              : //                 std::ptrdiff_t const len2 = std::min(lt::default_block_size, int(piece_size2 - offset));
    1060              : //                 h2.update({buf, len2});
    1061              : //                 buf += len2;
    1062              : //                 offset += len2;
    1063              : //                 block_hashes[k] = h2.final();
    1064              : //             }
    1065              : //         }
    1066              : //         return lt::hasher(i->second).final();
    1067              : //     }
    1068              : //     lt::sha256_hash hash2(lt::piece_index_t const piece, int const offset, lt::storage_error &ec)
    1069              : //     {
    1070              : //         auto const i = m_file_data.find(piece);
    1071              : //         if (i == m_file_data.end())
    1072              : //         {
    1073              : //             ec.operation = lt::operation_t::file_read;
    1074              : //             ec.ec = boost::asio::error::eof;
    1075              : //             return {};
    1076              : //         }
    1077              : 
    1078              : //         int const piece_size = m_files.piece_size2(piece);
    1079              : 
    1080              : //         std::ptrdiff_t const len = std::min(lt::default_block_size, piece_size - offset);
    1081              : 
    1082              : //         lt::span<char const> b = {i->second.data() + offset, len};
    1083              : //         return lt::hasher256(b).final();
    1084              : //     }
    1085              : 
    1086              : // private:
    1087              : //     int piece_size(lt::piece_index_t piece) const
    1088              : //     {
    1089              : //         int const num_pieces = static_cast<int>((m_files.total_size() + m_files.piece_length() - 1) /
    1090              : //         m_files.piece_length()); return static_cast<int>(piece) < num_pieces - 1
    1091              : //                    ? m_files.piece_length()
    1092              : //                    : static_cast<int>(m_files.total_size() - std::int64_t(num_pieces - 1) * m_files.piece_length());
    1093              : //     }
    1094              : 
    1095              : //     lt::file_storage const &m_files;
    1096              : //     std::map<lt::piece_index_t, std::vector<char>> m_file_data;
    1097              : // };
    1098              : 
    1099              : // lt::storage_index_t pop(std::vector<lt::storage_index_t> &q)
    1100              : // {
    1101              : //     TORRENT_ASSERT(!q.empty());
    1102              : //     lt::storage_index_t const ret = q.back();
    1103              : //     q.pop_back();
    1104              : //     return ret;
    1105              : // }
    1106              : 
    1107              : // struct temp_disk_io final : lt::disk_interface, lt::buffer_allocator_interface
    1108              : // {
    1109              : //     explicit temp_disk_io(lt::io_context &ioc) : m_ioc(ioc) {}
    1110              : 
    1111              : //     void settings_updated() override {}
    1112              : 
    1113              : //     lt::storage_holder new_torrent(lt::storage_params const &params, std::shared_ptr<void> const &) override
    1114              : //     {
    1115              : //         lt::storage_index_t const idx = m_free_slots.empty()
    1116              : //                                             ? m_torrents.end_index()
    1117              : //                                             : pop(m_free_slots);
    1118              : //         auto storage = std::make_unique<temp_storage>(params.files);
    1119              : //         if (idx == m_torrents.end_index())
    1120              : //         {
    1121              : //             m_torrents.emplace_back(std::move(storage));
    1122              : //         }
    1123              : //         else
    1124              : //         {
    1125              : //             m_torrents[idx] = std::move(storage);
    1126              : //         }
    1127              : //         return lt::storage_holder(idx, *this);
    1128              : //     }
    1129              : 
    1130              : //     void remove_torrent(lt::storage_index_t const idx) override
    1131              : //     {
    1132              : //         m_torrents[idx].reset();
    1133              : //         m_free_slots.push_back(idx);
    1134              : //     }
    1135              : 
    1136              : //     void abort(bool) override {}
    1137              : 
    1138              : //     void async_read(lt::storage_index_t storage, lt::peer_request const &r, std::function<void(lt::disk_buffer_holder
    1139              : //     block, lt::storage_error const &se)> handler, lt::disk_job_flags_t) override
    1140              : //     {
    1141              : //         // this buffer is owned by the storage. It will remain valid for as
    1142              : //         // long as the torrent remains in the session. We don't need any lifetime
    1143              : //         // management of it.
    1144              : //         lt::storage_error error;
    1145              : //         lt::span<char const> b = m_torrents[storage]->readv(r, error);
    1146              : 
    1147              : //         post(m_ioc, [handler, error, b, this]
    1148              : //              { handler(lt::disk_buffer_holder(*this, const_cast<char *>(b.data()), int(b.size())), error); });
    1149              : //     }
    1150              : 
    1151              : //     bool async_write(lt::storage_index_t storage, lt::peer_request const &r, char const *buf,
    1152              : //     std::shared_ptr<lt::disk_observer>, std::function<void(lt::storage_error const &)> handler, lt::disk_job_flags_t)
    1153              : //     override
    1154              : //     {
    1155              : //         lt::span<char const> const b = {buf, r.length};
    1156              : 
    1157              : //         m_torrents[storage]->writev(b, r.piece, r.start);
    1158              : 
    1159              : //         post(m_ioc, [=]
    1160              : //              { handler(lt::storage_error()); });
    1161              : //         return false;
    1162              : //     }
    1163              : 
    1164              : //     void async_hash(lt::storage_index_t storage, lt::piece_index_t const piece, lt::span<lt::sha256_hash>
    1165              : //     block_hashes, lt::disk_job_flags_t, std::function<void(lt::piece_index_t, lt::sha1_hash const &,
    1166              : //     lt::storage_error const &)> handler) override
    1167              : //     {
    1168              : //         lt::storage_error error;
    1169              : //         lt::sha1_hash const hash = m_torrents[storage]->hash(piece, block_hashes, error);
    1170              : //         post(m_ioc, [=]
    1171              : //              { handler(piece, hash, error); });
    1172              : //     }
    1173              : 
    1174              : //     void async_hash2(lt::storage_index_t storage, lt::piece_index_t const piece, int const offset,
    1175              : //     lt::disk_job_flags_t, std::function<void(lt::piece_index_t, lt::sha256_hash const &, lt::storage_error const &)>
    1176              : //     handler) override
    1177              : //     {
    1178              : //         lt::storage_error error;
    1179              : //         lt::sha256_hash const hash = m_torrents[storage]->hash2(piece, offset, error);
    1180              : //         post(m_ioc, [=]
    1181              : //              { handler(piece, hash, error); });
    1182              : //     }
    1183              : 
    1184              : //     void async_move_storage(lt::storage_index_t, std::string p, lt::move_flags_t, std::function<void(lt::status_t,
    1185              : //     std::string const &, lt::storage_error const &)> handler) override
    1186              : //     {
    1187              : //         post(m_ioc, [=]
    1188              : //              { handler(lt::status_t::fatal_disk_error, p,
    1189              : //              lt::storage_error(lt::error_code(boost::system::errc::operation_not_supported, lt::system_category())));
    1190              : //              });
    1191              : //     }
    1192              : 
    1193              : //     void async_release_files(lt::storage_index_t, std::function<void()>) override {}
    1194              : 
    1195              : //     void async_delete_files(lt::storage_index_t, lt::remove_flags_t, std::function<void(lt::storage_error const &)>
    1196              : //     handler) override
    1197              : //     {
    1198              : //         post(m_ioc, [=]
    1199              : //              { handler(lt::storage_error()); });
    1200              : //     }
    1201              : 
    1202              : //     void async_check_files(lt::storage_index_t, lt::add_torrent_params const *, lt::aux::vector<std::string,
    1203              : //     lt::file_index_t>, std::function<void(lt::status_t, lt::storage_error const &)> handler) override
    1204              : //     {
    1205              : //         post(m_ioc, [=]
    1206              : //              { handler(lt::status_t::no_error, lt::storage_error()); });
    1207              : //     }
    1208              : 
    1209              : //     void async_rename_file(lt::storage_index_t, lt::file_index_t const idx, std::string const name,
    1210              : //     std::function<void(std::string const &, lt::file_index_t, lt::storage_error const &)> handler) override
    1211              : //     {
    1212              : //         post(m_ioc, [=]
    1213              : //              { handler(name, idx, lt::storage_error()); });
    1214              : //     }
    1215              : 
    1216              : //     void async_stop_torrent(lt::storage_index_t, std::function<void()> handler) override
    1217              : //     {
    1218              : //         post(m_ioc, handler);
    1219              : //     }
    1220              : 
    1221              : //     void async_set_file_priority(lt::storage_index_t, lt::aux::vector<lt::download_priority_t, lt::file_index_t>
    1222              : //     prio, std::function<void(lt::storage_error const &, lt::aux::vector<lt::download_priority_t, lt::file_index_t>)>
    1223              : //     handler) override
    1224              : //     {
    1225              : //         post(m_ioc, [=]
    1226              : //              { handler(lt::storage_error(lt::error_code(
    1227              : //                            boost::system::errc::operation_not_supported, lt::system_category())),
    1228              : //                        std::move(prio)); });
    1229              : //     }
    1230              : 
    1231              : //     void async_clear_piece(lt::storage_index_t, lt::piece_index_t index, std::function<void(lt::piece_index_t)>
    1232              : //     handler) override
    1233              : //     {
    1234              : //         post(m_ioc, [=]
    1235              : //              { handler(index); });
    1236              : //     }
    1237              : 
    1238              : //     // implements buffer_allocator_interface
    1239              : //     void free_disk_buffer(char *) override
    1240              : //     {
    1241              : //         // never free any buffer. We only return buffers owned by the storage
    1242              : //         // object
    1243              : //     }
    1244              : 
    1245              : //     void update_stats_counters(lt::counters &) const override {}
    1246              : 
    1247              : //     std::vector<lt::open_file_state> get_status(lt::storage_index_t) const override
    1248              : //     {
    1249              : //         return {};
    1250              : //     }
    1251              : 
    1252              : //     void submit_jobs() override {}
    1253              : 
    1254              : // private:
    1255              : //     lt::aux::vector<std::shared_ptr<temp_storage>, lt::storage_index_t> m_torrents;
    1256              : 
    1257              : //     // slots that are unused in the m_torrents vector
    1258              : //     std::vector<lt::storage_index_t> m_free_slots;
    1259              : 
    1260              : //     // callbacks are posted on this
    1261              : //     lt::io_context &m_ioc;
    1262              : // };
    1263              : 
    1264              : // std::unique_ptr<lt::disk_interface> temp_disk_constructor(
    1265              : //     lt::io_context &ioc, lt::settings_interface const &, lt::counters &)
    1266              : // {
    1267              : //     return std::make_unique<temp_disk_io>(ioc);
    1268              : // }
    1269              : 
    1270              : } // namespace dunedaq::snbmodules
        

Generated by: LCOV version 2.0-1