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 ¶ms, 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
|