1 /*
2
3 Copyright (c) 2015, Arvid Norberg
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30
31 */
32
33 #include <array>
34 #include "test.hpp"
35 #include "create_torrent.hpp"
36 #include "settings.hpp"
37 #include "libtorrent/session.hpp"
38 #include "libtorrent/session_stats.hpp"
39 #include "libtorrent/settings_pack.hpp"
40 #include "libtorrent/ip_filter.hpp"
41 #include "libtorrent/alert_types.hpp"
42 #include "libtorrent/aux_/proxy_settings.hpp"
43 #include "libtorrent/settings_pack.hpp"
44 #include "simulator/simulator.hpp"
45 #include "simulator/socks_server.hpp"
46 #include "simulator/utils.hpp"
47 #include "setup_swarm.hpp"
48 #include "utils.hpp"
49 #include "setup_transfer.hpp" // for addr()
50
51 using namespace sim;
52
53
make_ep_string(char const * address,bool const is_v6,char const * port)54 std::string make_ep_string(char const* address, bool const is_v6
55 , char const* port)
56 {
57 std::string ret;
58 if (is_v6) ret += '[';
59 ret += address;
60 if (is_v6) ret += ']';
61 ret += ':';
62 ret += port;
63 return ret;
64 }
65
66 template <typename Setup, typename HandleAlerts, typename Test>
run_test(Setup const & setup,HandleAlerts const & on_alert,Test const & test,int flags=0)67 void run_test(
68 Setup const& setup
69 , HandleAlerts const& on_alert
70 , Test const& test
71 , int flags = 0)
72 {
73 using namespace lt;
74
75 const bool use_ipv6 = flags & ipv6;
76
77 char const* peer0_ip[2] = { "50.0.0.1", "feed:face:baad:f00d::1" };
78 char const* peer1_ip[2] = { "50.0.0.2", "feed:face:baad:f00d::2" };
79
80 using asio::ip::address;
81 address peer0 = addr(peer0_ip[use_ipv6]);
82 address peer1 = addr(peer1_ip[use_ipv6]);
83 address proxy = (flags & ipv6) ? addr("2001::2") : addr("50.50.50.50");
84
85 // setup the simulation
86 sim::default_config network_cfg;
87 sim::simulation sim{network_cfg};
88 sim::asio::io_service ios0 { sim, peer0 };
89 sim::asio::io_service ios1 { sim, peer1 };
90
91 lt::session_proxy zombie[2];
92
93 sim::asio::io_service proxy_ios{sim, proxy };
94 sim::socks_server socks4(proxy_ios, 4444, 4);
95 sim::socks_server socks5(proxy_ios, 5555, 5);
96
97 // setup settings pack to use for the session (customization point)
98 lt::settings_pack pack = settings();
99
100 // disable utp by default
101 pack.set_bool(settings_pack::enable_outgoing_utp, false);
102 pack.set_bool(settings_pack::enable_incoming_utp, false);
103
104 // disable encryption by default
105 pack.set_bool(settings_pack::prefer_rc4, false);
106 pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled);
107 pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled);
108 pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_plaintext);
109
110 pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer0_ip[use_ipv6], use_ipv6, "6881"));
111
112 // create session
113 std::shared_ptr<lt::session> ses[2];
114 ses[0] = std::make_shared<lt::session>(pack, ios0);
115
116 pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer1_ip[use_ipv6], use_ipv6, "6881"));
117 ses[1] = std::make_shared<lt::session>(pack, ios1);
118
119 setup(*ses[0], *ses[1]);
120
121 // only monitor alerts for session 0 (the downloader)
122 print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
123 if (auto ta = alert_cast<lt::add_torrent_alert>(a))
124 {
125 ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
126 }
127 on_alert(ses, a);
128 }, 0);
129
130 print_alerts(*ses[1], [](lt::session&, lt::alert const*){}, 1);
131
132 // the first peer is a downloader, the second peer is a seed
133 lt::add_torrent_params params = ::create_torrent(1);
134 params.flags &= ~lt::torrent_flags::auto_managed;
135 params.flags &= ~lt::torrent_flags::paused;
136
137 params.save_path = save_path(0);
138 ses[0]->async_add_torrent(params);
139
140 params.save_path = save_path(1);
141 ses[1]->async_add_torrent(params);
142
143 sim::timer t(sim, lt::seconds(60), [&](boost::system::error_code const&)
144 {
145 test(ses);
146
147 // shut down
148 int idx = 0;
149 for (auto& s : ses)
150 {
151 zombie[idx++] = s->abort();
152 s.reset();
153 }
154 });
155
156 sim.run();
157 }
158
TORRENT_TEST(socks4_tcp)159 TORRENT_TEST(socks4_tcp)
160 {
161 using namespace lt;
162 run_test(
163 [](lt::session& ses0, lt::session& ses1)
164 {
165 set_proxy(ses0, settings_pack::socks4);
166 filter_ips(ses1);
167 },
168 [](lt::session&, lt::alert const*) {},
169 [](std::shared_ptr<lt::session> ses[2]) {
170 TEST_EQUAL(is_seed(*ses[0]), true);
171 }
172 );
173 }
174
TORRENT_TEST(socks5_tcp_connect)175 TORRENT_TEST(socks5_tcp_connect)
176 {
177 using namespace lt;
178 run_test(
179 [](lt::session& ses0, lt::session& ses1)
180 {
181 set_proxy(ses0, settings_pack::socks5);
182 filter_ips(ses1);
183 },
184 [](lt::session&, lt::alert const*) {},
185 [](std::shared_ptr<lt::session> ses[2]) {
186 TEST_EQUAL(is_seed(*ses[0]), true);
187 }
188 );
189 }
190
TORRENT_TEST(encryption_tcp)191 TORRENT_TEST(encryption_tcp)
192 {
193 using namespace lt;
194 run_test(
195 [](lt::session& ses0, lt::session& ses1)
196 { enable_enc(ses0); enable_enc(ses1); },
197 [](lt::session&, lt::alert const*) {},
198 [](std::shared_ptr<lt::session> ses[2]) {
199 TEST_EQUAL(is_seed(*ses[0]), true);
200 }
201 );
202 }
203
TORRENT_TEST(no_proxy_tcp_ipv6)204 TORRENT_TEST(no_proxy_tcp_ipv6)
205 {
206 using namespace lt;
207 run_test(
208 [](lt::session&, lt::session&) {},
209 [](lt::session&, lt::alert const*) {},
210 [](std::shared_ptr<lt::session> ses[2]) {
211 TEST_EQUAL(is_seed(*ses[0]), true);
212 },
213 ipv6
214 );
215 }
216
TORRENT_TEST(no_proxy_utp_ipv6)217 TORRENT_TEST(no_proxy_utp_ipv6)
218 {
219 using namespace lt;
220 run_test(
221 [](lt::session& ses0, lt::session& ses1)
222 { utp_only(ses0); utp_only(ses1); },
223 [](lt::session&, lt::alert const*) {},
224 [](std::shared_ptr<lt::session> ses[2]) {
225 TEST_EQUAL(is_seed(*ses[0]), true);
226 },
227 ipv6
228 );
229 }
230
231 // TODO: the socks server does not support IPv6 addresses yet
232 /*
233 TORRENT_TEST(socks5_tcp_ipv6)
234 {
235 using namespace lt;
236 run_test(
237 [](lt::session& ses0, lt::session& ses1)
238 {
239 set_proxy(ses0, settings_pack::socks5);
240 filter_ips(ses1);
241 },
242 [](lt::session&, lt::alert const*) {},
243 [](std::shared_ptr<lt::session> ses[2]) {
244 TEST_EQUAL(is_seed(*ses[0]), true);
245 },
246 ipv6
247 );
248 }
249 */
250
TORRENT_TEST(no_proxy_tcp)251 TORRENT_TEST(no_proxy_tcp)
252 {
253 using namespace lt;
254 run_test(
255 [](lt::session&, lt::session&) {},
256 [](lt::session&, lt::alert const*) {},
257 [](std::shared_ptr<lt::session> ses[2]) {
258 TEST_EQUAL(is_seed(*ses[0]), true);
259 }
260 );
261 }
262
TORRENT_TEST(no_proxy_utp)263 TORRENT_TEST(no_proxy_utp)
264 {
265 using namespace lt;
266 run_test(
267 [](lt::session& ses0, lt::session& ses1)
268 { utp_only(ses0); utp_only(ses1); },
269 [](lt::session&, lt::alert const*) {},
270 [](std::shared_ptr<lt::session> ses[2]) {
271 TEST_EQUAL(is_seed(*ses[0]), true);
272 }
273 );
274 }
275
TORRENT_TEST(encryption_utp)276 TORRENT_TEST(encryption_utp)
277 {
278 using namespace lt;
279 run_test(
280 [](lt::session& ses0, lt::session& ses1)
281 {
282 enable_enc(ses0);
283 enable_enc(ses1);
284 utp_only(ses0);
285 utp_only(ses1);
286 },
287 [](lt::session&, lt::alert const*) {},
288 [](std::shared_ptr<lt::session> ses[2]) {
289 TEST_EQUAL(is_seed(*ses[0]), true);
290 }
291 );
292 }
293
TORRENT_TEST(socks5_utp)294 TORRENT_TEST(socks5_utp)
295 {
296 using namespace lt;
297 run_test(
298 [](lt::session& ses0, lt::session& ses1)
299 {
300 set_proxy(ses0, settings_pack::socks5);
301 utp_only(ses0);
302 filter_ips(ses1);
303 utp_only(ses1);
304 },
305 [](lt::session&, lt::alert const*) {},
306 [](std::shared_ptr<lt::session> ses[2]) {
307 TEST_EQUAL(is_seed(*ses[0]), true);
308 }
309 );
310 }
311
312 // the purpose of these tests is to make sure that the sessions can't actually
313 // talk directly to each other. i.e. they are negative tests. If they can talk
314 // directly to each other, all other tests in here may be broken.
TORRENT_TEST(no_proxy_tcp_banned)315 TORRENT_TEST(no_proxy_tcp_banned)
316 {
317 using namespace lt;
318 run_test(
319 [](lt::session&, lt::session& ses1) { filter_ips(ses1); },
320 [](lt::session&, lt::alert const*) {},
321 [](std::shared_ptr<lt::session> ses[2]) {
322 TEST_EQUAL(is_seed(*ses[0]), false);
323 }
324 );
325 }
326
TORRENT_TEST(no_proxy_utp_banned)327 TORRENT_TEST(no_proxy_utp_banned)
328 {
329 using namespace lt;
330 run_test(
331 [](lt::session& ses0, lt::session& ses1)
332 { utp_only(ses0); utp_only(ses1); filter_ips(ses1); },
333 [](lt::session&, lt::alert const*) {},
334 [](std::shared_ptr<lt::session> ses[2]) {
335 TEST_EQUAL(is_seed(*ses[0]), false);
336 }
337 );
338 }
339
TORRENT_TEST(auto_disk_cache_size)340 TORRENT_TEST(auto_disk_cache_size)
341 {
342 using namespace lt;
343 run_test(
344 [](lt::session& ses0, lt::session&) { set_cache_size(ses0, -1); },
345 [](lt::session&, lt::alert const*) {},
346 [](std::shared_ptr<lt::session> ses[2]) {
347 TEST_EQUAL(is_seed(*ses[0]), true);
348
349 int const cache_size = get_cache_size(*ses[0]);
350 std::printf("cache size: %d\n", cache_size);
351 // this assumes the test torrent is at least 4 blocks
352 TEST_CHECK(cache_size > 4);
353 }
354 );
355 }
356
TORRENT_TEST(disable_disk_cache)357 TORRENT_TEST(disable_disk_cache)
358 {
359 using namespace lt;
360 run_test(
361 [](lt::session& ses0, lt::session&) { set_cache_size(ses0, 0); },
362 [](lt::session&, lt::alert const*) {},
363 [](std::shared_ptr<lt::session> ses[2]) {
364 TEST_EQUAL(is_seed(*ses[0]), true);
365
366 int const cache_size = get_cache_size(*ses[0]);
367 std::printf("cache size: %d\n", cache_size);
368 TEST_EQUAL(cache_size, 0);
369 }
370 );
371 }
372
TORRENT_TEST(piece_extent_affinity)373 TORRENT_TEST(piece_extent_affinity)
374 {
375 using namespace lt;
376 run_test(
377 [](lt::session& ses0, lt::session& ses1)
378 {
379 settings_pack p;
380 p.set_bool(settings_pack::piece_extent_affinity, true);
381 ses0.apply_settings(p);
382 ses1.apply_settings(p);
383 },
384 [](lt::session&, lt::alert const*) {},
385 [](std::shared_ptr<lt::session> ses[2]) {
386 TEST_EQUAL(is_seed(*ses[0]), true);
387 }
388 );
389 }
390
TORRENT_TEST(is_finished)391 TORRENT_TEST(is_finished)
392 {
393 using namespace lt;
394 run_test(
395 [](lt::session&, lt::session&) {},
396 [](lt::session& ses, lt::alert const* a) {
397 if (alert_cast<piece_finished_alert>(a))
398 {
399 TEST_EQUAL(is_finished(ses), false);
400 std::vector<download_priority_t> prio(4, dont_download);
401 ses.get_torrents()[0].prioritize_files(prio);
402 // applying the priorities is asynchronous. the torrent may not
403 // finish immediately
404 }
405 },
406 [](std::shared_ptr<lt::session> ses[2]) {
407 TEST_EQUAL(is_finished(*ses[0]), true);
408 TEST_EQUAL(is_finished(*ses[1]), true);
409 }
410 );
411 }
412
413