GCC Code Coverage Report


src/
File: src/examples/tor.cpp
Date: 2026-03-31 17:48:22
Lines:
0/106
0.0%
Functions:
0/4
0.0%
Branches:
0/106
0.0%

Line Branch Exec Source
1 #include <chrono>
2 #include <csignal>
3 #include <fstream>
4 #include <iostream>
5 #include <string>
6 #include <thread>
7 #include <utility>
8 #include <vector>
9 #include <libtorrent/add_torrent_params.hpp>
10 #include <libtorrent/alert_types.hpp>
11 #include <libtorrent/bencode.hpp>
12 #include <libtorrent/error_code.hpp>
13 #include <libtorrent/magnet_uri.hpp>
14 #include <libtorrent/read_resume_data.hpp>
15 #include <libtorrent/session.hpp>
16 #include <libtorrent/session_params.hpp>
17 #include <libtorrent/torrent_handle.hpp>
18 #include <libtorrent/torrent_status.hpp>
19 #include <libtorrent/write_resume_data.hpp>
20 #include "examples/tor.h"
21
22 namespace {
23
24 using clk = std::chrono::steady_clock;
25
26 // return the name of a torrent status enum
27 char const* state(lt::torrent_status::state_t s) {
28 #ifdef __clang__
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wcovered-switch-default"
31 #endif
32 switch (s) {
33 case lt::torrent_status::checking_files:
34 return "checking";
35 case lt::torrent_status::downloading_metadata:
36 return "retrieving metadata";
37 case lt::torrent_status::downloading:
38 return "downloading";
39 case lt::torrent_status::finished:
40 return "finished";
41 case lt::torrent_status::seeding:
42 return "seeding";
43 case lt::torrent_status::checking_resume_data:
44 return "checking resume";
45 default:
46 return "<>";
47 }
48 #ifdef __clang__
49 #pragma clang diagnostic pop
50 #endif
51 }
52
53 std::vector<char> load_file(char const* filename) {
54 std::ifstream ifs(filename, std::ios_base::binary);
55 ifs.unsetf(std::ios_base::skipws);
56 return {std::istream_iterator<char>(ifs), std::istream_iterator<char>()};
57 }
58
59 // set when we're exiting
60 std::atomic<bool> shut_down{false};
61
62 void sighandler(int) {
63 shut_down = true;
64 }
65
66 } // anonymous namespace
67
68 int torrent_example() try {
69 auto magnet_uri =
70 "magnet:?xt=urn:btih:0cc30ccd5366088882f1e7a2bb6f55d66e703c8e&xt=urn:"
71 "btmh:"
72 "122070888da130f26beb551d7513c7afaa9a85546ddf75d339bcdadb0151032f0f22&"
73 "dn=.git&tr=http%3A%2F%2Ftracker.renfei.net%3A8080%2Fannounce&tr=udp%"
74 "3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=https%3A%2F%"
75 "2Ftracker.jdx3.org%3A443%2Fannounce";
76
77 const std::string dir = "tor/";
78
79 // load session parameters
80 auto session_params = load_file((dir + ".session").c_str());
81 lt::session_params params = session_params.empty()
82 ? lt::session_params()
83 : lt::read_session_params(session_params);
84 params.settings.set_int(lt::settings_pack::alert_mask,
85 lt::alert_category::error |
86 lt::alert_category::storage |
87 lt::alert_category::status);
88
89 lt::session ses(params);
90 clk::time_point last_save_resume = clk::now();
91
92 // load resume data from disk and pass it in as we add the magnet link
93 auto buf = load_file((dir + ".resume_file").c_str());
94
95 lt::add_torrent_params magnet = lt::parse_magnet_uri(magnet_uri);
96 if (buf.size()) {
97 lt::add_torrent_params atp = lt::read_resume_data(buf);
98 if (atp.info_hashes == magnet.info_hashes)
99 magnet = std::move(atp);
100 }
101 magnet.save_path = dir; // save in current dir
102 ses.async_add_torrent(std::move(magnet));
103
104 // this is the handle we'll set once we get the notification of it being
105 // added
106 lt::torrent_handle h;
107
108 std::signal(SIGINT, &sighandler);
109
110 // set when we're exiting
111 bool done = false;
112 for (;;) {
113 std::vector<lt::alert*> alerts;
114 ses.pop_alerts(&alerts);
115
116 if (shut_down) {
117 shut_down = false;
118 auto const handles = ses.get_torrents();
119 if (handles.size() == 1) {
120 handles[0].save_resume_data(
121 lt::torrent_handle::only_if_modified |
122 lt::torrent_handle::save_info_dict);
123 done = true;
124 }
125 }
126
127 for (lt::alert const* a : alerts) {
128 if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
129 h = at->handle;
130 }
131 // if we receive the finished alert or an error, we're done
132 if (lt::alert_cast<lt::torrent_finished_alert>(a)) {
133 h.save_resume_data(lt::torrent_handle::only_if_modified |
134 lt::torrent_handle::save_info_dict);
135 done = true;
136 }
137 if (lt::alert_cast<lt::torrent_error_alert>(a)) {
138 std::cout << a->message() << '\n';
139 done = true;
140 h.save_resume_data(lt::torrent_handle::only_if_modified |
141 lt::torrent_handle::save_info_dict);
142 }
143
144 // when resume data is ready, save it
145 if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) {
146 std::ofstream of(dir + ".resume_file", std::ios_base::binary);
147 of.unsetf(std::ios_base::skipws);
148 auto const b = write_resume_data_buf(rd->params);
149 of.write(b.data(), static_cast<int>(b.size()));
150 if (done)
151 goto done;
152 }
153
154 if (lt::alert_cast<lt::save_resume_data_failed_alert>(a)) {
155 if (done)
156 goto done;
157 }
158
159 if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
160 if (st->status.empty())
161 continue;
162
163 // we only have a single torrent, so we know which one
164 // the status is for
165 lt::torrent_status const& s = st->status[0];
166 std::cout << '\r' << state(s.state) << ' '
167 << (s.download_payload_rate / 1000) << " kB/s "
168 << (s.total_done / 1000) << " kB ("
169 << (s.progress_ppm / 10000) << "%) downloaded ("
170 << s.num_peers << " peers)\x1b[K";
171 std::cout.flush();
172 }
173 }
174 std::this_thread::sleep_for(std::chrono::milliseconds(200));
175
176 // ask the session to post a state_update_alert, to update our
177 // state output for the torrent
178 ses.post_torrent_updates();
179
180 // save resume data once every 30 seconds
181 if (clk::now() - last_save_resume > std::chrono::seconds(30)) {
182 h.save_resume_data(lt::torrent_handle::only_if_modified |
183 lt::torrent_handle::save_info_dict);
184 last_save_resume = clk::now();
185 }
186 }
187
188 done:
189 std::cout << "\nsaving session state" << '\n';
190 {
191 std::ofstream of(dir + ".session", std::ios_base::binary);
192 of.unsetf(std::ios_base::skipws);
193 auto const b = write_session_params_buf(ses.session_state(),
194 lt::save_state_flags_t::all());
195 of.write(b.data(), static_cast<int>(b.size()));
196 }
197
198 std::cout << "\ndone, shutting down" << '\n';
199 return 0;
200 } catch (std::exception& e) {
201 std::cerr << "Error: " << e.what() << '\n';
202 return 1;
203 }
204