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