1 /*
2 
3 Copyright (c) 2013, 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 "libtorrent/peer_list.hpp"
34 #include "libtorrent/torrent_handle.hpp"
35 #include "libtorrent/torrent_peer_allocator.hpp"
36 #include "libtorrent/peer_connection_interface.hpp"
37 #include "libtorrent/stat.hpp"
38 #include "libtorrent/ip_voter.hpp"
39 #include "libtorrent/ip_filter.hpp"
40 #include "libtorrent/peer_info.hpp"
41 #include "libtorrent/random.hpp"
42 #include "libtorrent/socket_io.hpp"
43 
44 #include "test.hpp"
45 #include "setup_transfer.hpp"
46 #include <vector>
47 #include <memory> // for shared_ptr
48 #include <cstdarg>
49 
50 using namespace lt;
51 
52 namespace {
53 
54 struct mock_torrent;
55 
56 struct mock_peer_connection
57 	: peer_connection_interface
58 	, std::enable_shared_from_this<mock_peer_connection>
59 {
mock_peer_connection__anon8b1829440111::mock_peer_connection60 	mock_peer_connection(mock_torrent* tor, bool out, tcp::endpoint const& remote)
61 		: m_choked(false)
62 		, m_outgoing(out)
63 		, m_tp(nullptr)
64 		, m_remote(remote)
65 		, m_local(ep("127.0.0.1", 8080))
66 		, m_our_id(nullptr)
67 		, m_disconnect_called(false)
68 		, m_torrent(*tor)
69 	{
70 		aux::random_bytes(m_id);
71 	}
72 
73 	virtual ~mock_peer_connection() = default;
74 
75 #if !defined TORRENT_DISABLE_LOGGING
should_log__anon8b1829440111::mock_peer_connection76 	bool should_log(peer_log_alert::direction_t) const noexcept override
77 	{ return true; }
78 
peer_log__anon8b1829440111::mock_peer_connection79 	void peer_log(peer_log_alert::direction_t, char const* /*event*/
80 		, char const* fmt, ...) const noexcept override
81 	{
82 		va_list v;
83 		va_start(v, fmt);
84 #ifdef __clang__
85 #pragma clang diagnostic push
86 #pragma clang diagnostic ignored "-Wformat-nonliteral"
87 #endif
88 		std::vprintf(fmt, v);
89 #ifdef __clang__
90 #pragma clang diagnostic pop
91 #endif
92 		va_end(v);
93 	}
94 #endif
95 
was_disconnected__anon8b1829440111::mock_peer_connection96 	bool was_disconnected() const { return m_disconnect_called; }
set_local_ep__anon8b1829440111::mock_peer_connection97 	void set_local_ep(tcp::endpoint const& ep) { m_local = ep; }
98 
99 	lt::stat m_stat;
100 	bool m_choked;
101 	bool m_outgoing;
102 	torrent_peer* m_tp;
103 	tcp::endpoint m_remote;
104 	tcp::endpoint m_local;
105 	peer_id m_id;
106 	peer_id m_our_id;
107 	bool m_disconnect_called;
108 	mock_torrent& m_torrent;
109 
get_peer_info__anon8b1829440111::mock_peer_connection110 	void get_peer_info(peer_info&) const override {}
remote__anon8b1829440111::mock_peer_connection111 	tcp::endpoint const& remote() const override { return m_remote; }
local_endpoint__anon8b1829440111::mock_peer_connection112 	tcp::endpoint local_endpoint() const override { return m_local; }
113 	void disconnect(error_code const& ec
114 		, operation_t op, disconnect_severity_t error = peer_connection_interface::normal) override;
pid__anon8b1829440111::mock_peer_connection115 	peer_id const& pid() const override { return m_id; }
our_pid__anon8b1829440111::mock_peer_connection116 	peer_id our_pid() const override { return m_our_id; }
set_holepunch_mode__anon8b1829440111::mock_peer_connection117 	void set_holepunch_mode() override {}
peer_info_struct__anon8b1829440111::mock_peer_connection118 	torrent_peer* peer_info_struct() const override { return m_tp; }
set_peer_info__anon8b1829440111::mock_peer_connection119 	void set_peer_info(torrent_peer* pi) override { m_tp = pi; }
is_outgoing__anon8b1829440111::mock_peer_connection120 	bool is_outgoing() const override { return m_outgoing; }
add_stat__anon8b1829440111::mock_peer_connection121 	void add_stat(std::int64_t downloaded, std::int64_t uploaded) override
122 	{ m_stat.add_stat(downloaded, uploaded); }
fast_reconnect__anon8b1829440111::mock_peer_connection123 	bool fast_reconnect() const override { return true; }
is_choked__anon8b1829440111::mock_peer_connection124 	bool is_choked() const override { return m_choked; }
failed__anon8b1829440111::mock_peer_connection125 	bool failed() const override { return false; }
statistics__anon8b1829440111::mock_peer_connection126 	lt::stat const& statistics() const override { return m_stat; }
127 };
128 
129 struct mock_torrent
130 {
mock_torrent__anon8b1829440111::mock_torrent131 	explicit mock_torrent(torrent_state* st) : m_p(nullptr), m_state(st) {}
132 	virtual ~mock_torrent() = default;
133 
connect_to_peer__anon8b1829440111::mock_torrent134 	bool connect_to_peer(torrent_peer* peerinfo)
135 	{
136 		TORRENT_ASSERT(peerinfo->connection == nullptr);
137 		if (peerinfo->connection) return false;
138 		auto c = std::make_shared<mock_peer_connection>(this, true, peerinfo->ip());
139 		c->set_peer_info(peerinfo);
140 
141 		m_connections.push_back(c);
142 		m_p->set_connection(peerinfo, c.get());
143 		return true;
144 	}
145 
146 	peer_list* m_p;
147 	torrent_state* m_state;
148 	std::vector<std::shared_ptr<mock_peer_connection>> m_connections;
149 };
150 
disconnect(error_code const &,operation_t,disconnect_severity_t)151 void mock_peer_connection::disconnect(error_code const&
152 	, operation_t, disconnect_severity_t)
153 {
154 	m_torrent.m_p->connection_closed(*this, 0, m_torrent.m_state);
155 	auto const i = std::find(m_torrent.m_connections.begin(), m_torrent.m_connections.end()
156 		, std::static_pointer_cast<mock_peer_connection>(shared_from_this()));
157 	if (i != m_torrent.m_connections.end()) m_torrent.m_connections.erase(i);
158 
159 	m_tp = nullptr;
160 	m_disconnect_called = true;
161 }
162 
has_peer(peer_list const & p,tcp::endpoint const & ep)163 bool has_peer(peer_list const& p, tcp::endpoint const& ep)
164 {
165 	auto const its = p.find_peers(ep.address());
166 	return its.first != its.second;
167 }
168 
init_state()169 torrent_state init_state()
170 {
171 	torrent_state st;
172 	st.is_finished = false;
173 	st.max_peerlist_size = 1000;
174 	st.allow_multiple_connections_per_ip = false;
175 	st.port = 9999;
176 	return st;
177 }
178 
add_peer(peer_list & p,torrent_state & st,tcp::endpoint const & ep)179 torrent_peer* add_peer(peer_list& p, torrent_state& st, tcp::endpoint const& ep)
180 {
181 	int cc = p.num_connect_candidates();
182 	torrent_peer* peer = p.add_peer(ep, {}, {}, &st);
183 	if (peer)
184 	{
185 		TEST_EQUAL(p.num_connect_candidates(), cc + 1);
186 		TEST_EQUAL(peer->port, ep.port());
187 	}
188 	st.erased.clear();
189 	return peer;
190 }
191 
connect_peer(peer_list & p,mock_torrent & t,torrent_state & st)192 void connect_peer(peer_list& p, mock_torrent& t, torrent_state& st)
193 {
194 	torrent_peer* tp = p.connect_one_peer(0, &st);
195 	TEST_CHECK(tp);
196 	if (!tp) return;
197 	t.connect_to_peer(tp);
198 	st.erased.clear();
199 	TEST_CHECK(tp->connection);
200 }
201 
202 static torrent_peer_allocator allocator;
203 
204 } // anonymous namespace
205 
206 // test multiple peers with the same IP
207 // when disallowing it
TORRENT_TEST(multiple_ips_disallowed)208 TORRENT_TEST(multiple_ips_disallowed)
209 {
210 	torrent_state st = init_state();
211 	mock_torrent t(&st);
212 	peer_list p(allocator);
213 	t.m_p = &p;
214 	TEST_EQUAL(p.num_connect_candidates(), 0);
215 	torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), {}, {}, &st);
216 
217 	TEST_EQUAL(p.num_peers(), 1);
218 	TEST_EQUAL(p.num_connect_candidates(), 1);
219 	st.erased.clear();
220 
221 	torrent_peer* peer2 = p.add_peer(ep("10.0.0.2", 9020), {}, {}, &st);
222 	TEST_EQUAL(p.num_peers(), 1);
223 	TEST_EQUAL(peer1, peer2);
224 	TEST_EQUAL(p.num_connect_candidates(), 1);
225 	st.erased.clear();
226 }
227 
228 // test multiple peers with the same IP
229 // when allowing it
TORRENT_TEST(multiple_ips_allowed)230 TORRENT_TEST(multiple_ips_allowed)
231 {
232 	torrent_state st = init_state();
233 	mock_torrent t(&st);
234 	st.allow_multiple_connections_per_ip = true;
235 	peer_list p(allocator);
236 	t.m_p = &p;
237 	torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), {}, {}, &st);
238 	TEST_EQUAL(p.num_connect_candidates(), 1);
239 	TEST_EQUAL(p.num_peers(), 1);
240 	st.erased.clear();
241 
242 	torrent_peer* peer2 = p.add_peer(ep("10.0.0.2", 9020), {}, {}, &st);
243 	TEST_EQUAL(p.num_peers(), 2);
244 	TEST_CHECK(peer1 != peer2);
245 	TEST_EQUAL(p.num_connect_candidates(), 2);
246 	st.erased.clear();
247 }
248 
249 // test adding two peers with the same IP, but different ports, to
250 // make sure they can be connected at the same time
251 // with allow_multiple_connections_per_ip enabled
TORRENT_TEST(multiple_ips_allowed2)252 TORRENT_TEST(multiple_ips_allowed2)
253 {
254 	torrent_state st = init_state();
255 	mock_torrent t(&st);
256 	st.allow_multiple_connections_per_ip = true;
257 	peer_list p(allocator);
258 	t.m_p = &p;
259 	torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), {}, {}, &st);
260 	TEST_EQUAL(p.num_connect_candidates(), 1);
261 	st.erased.clear();
262 
263 	TEST_EQUAL(p.num_peers(), 1);
264 	torrent_peer* tp = p.connect_one_peer(0, &st);
265 	TEST_CHECK(tp);
266 	t.connect_to_peer(tp);
267 	st.erased.clear();
268 
269 	// we only have one peer, we can't
270 	// connect another one
271 	tp = p.connect_one_peer(0, &st);
272 	TEST_CHECK(tp == nullptr);
273 	st.erased.clear();
274 
275 	torrent_peer* peer2 = p.add_peer(ep("10.0.0.2", 9020), {}, {}, &st);
276 	TEST_EQUAL(p.num_peers(), 2);
277 	TEST_CHECK(peer1 != peer2);
278 	TEST_EQUAL(p.num_connect_candidates(), 1);
279 	st.erased.clear();
280 
281 	tp = p.connect_one_peer(0, &st);
282 	TEST_CHECK(tp);
283 	t.connect_to_peer(tp);
284 	TEST_EQUAL(p.num_connect_candidates(), 0);
285 	st.erased.clear();
286 }
287 
288 // test adding two peers with the same IP, but different ports, to
289 // make sure they can not be connected at the same time
290 // with allow_multiple_connections_per_ip disabled
TORRENT_TEST(multiple_ips_disallowed2)291 TORRENT_TEST(multiple_ips_disallowed2)
292 {
293 	torrent_state st = init_state();
294 	mock_torrent t(&st);
295 	st.allow_multiple_connections_per_ip = false;
296 	peer_list p(allocator);
297 	t.m_p = &p;
298 	torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), {}, {}, &st);
299 	TEST_EQUAL(p.num_connect_candidates(), 1);
300 	TEST_EQUAL(peer1->port, 3000);
301 	st.erased.clear();
302 
303 	TEST_EQUAL(p.num_peers(), 1);
304 	torrent_peer* tp = p.connect_one_peer(0, &st);
305 	TEST_CHECK(tp);
306 	t.connect_to_peer(tp);
307 	st.erased.clear();
308 
309 	// we only have one peer, we can't
310 	// connect another one
311 	tp = p.connect_one_peer(0, &st);
312 	TEST_CHECK(tp == nullptr);
313 	st.erased.clear();
314 
315 	torrent_peer* peer2 = p.add_peer(ep("10.0.0.2", 9020), {}, {}, &st);
316 	TEST_EQUAL(p.num_peers(), 1);
317 	TEST_EQUAL(peer2->port, 9020);
318 		TEST_CHECK(peer1 == peer2);
319 	TEST_EQUAL(p.num_connect_candidates(), 0);
320 	st.erased.clear();
321 }
322 
323 // test incoming connection
324 // and update_peer_port
TORRENT_TEST(update_peer_port)325 TORRENT_TEST(update_peer_port)
326 {
327 	torrent_state st = init_state();
328 	mock_torrent t(&st);
329 	st.allow_multiple_connections_per_ip = false;
330 	peer_list p(allocator);
331 	t.m_p = &p;
332 	TEST_EQUAL(p.num_connect_candidates(), 0);
333 	auto c = std::make_shared<mock_peer_connection>(&t, true, ep("10.0.0.1", 8080));
334 	p.new_connection(*c, 0, &st);
335 	TEST_EQUAL(p.num_connect_candidates(), 0);
336 	TEST_EQUAL(p.num_peers(), 1);
337 	st.erased.clear();
338 
339 	p.update_peer_port(4000, c->peer_info_struct(), peer_info::incoming, &st);
340 	TEST_EQUAL(p.num_connect_candidates(), 0);
341 	TEST_EQUAL(p.num_peers(), 1);
342 	TEST_EQUAL(c->peer_info_struct()->port, 4000);
343 	st.erased.clear();
344 }
345 
346 // test incoming connection
347 // and update_peer_port, causing collission
TORRENT_TEST(update_peer_port_collide)348 TORRENT_TEST(update_peer_port_collide)
349 {
350 	torrent_state st = init_state();
351 	mock_torrent t(&st);
352 	st.allow_multiple_connections_per_ip = true;
353 	peer_list p(allocator);
354 	t.m_p = &p;
355 
356 	torrent_peer* peer2 = p.add_peer(ep("10.0.0.1", 4000), {}, {}, &st);
357 	TEST_CHECK(peer2);
358 
359 	TEST_EQUAL(p.num_connect_candidates(), 1);
360 	auto c = std::make_shared<mock_peer_connection>(&t, true, ep("10.0.0.1", 8080));
361 	p.new_connection(*c, 0, &st);
362 	TEST_EQUAL(p.num_connect_candidates(), 1);
363 	// at this point we have two peers, because we think they have different
364 	// ports
365 	TEST_EQUAL(p.num_peers(), 2);
366 	st.erased.clear();
367 
368 		// this peer will end up having the same port as the existing peer in the list
369 	p.update_peer_port(4000, c->peer_info_struct(), peer_info::incoming, &st);
370 	TEST_EQUAL(p.num_connect_candidates(), 0);
371 	// the expected behavior is to replace that one
372 	TEST_EQUAL(p.num_peers(), 1);
373 	TEST_EQUAL(c->peer_info_struct()->port, 4000);
374 	st.erased.clear();
375 }
376 
377 namespace {
shared_from_this(lt::peer_connection_interface * p)378 std::shared_ptr<mock_peer_connection> shared_from_this(lt::peer_connection_interface* p)
379 {
380 	return std::static_pointer_cast<mock_peer_connection>(
381 		static_cast<mock_peer_connection*>(p)->shared_from_this());
382 }
383 } // anonymous namespace
384 
385 // test ip filter
TORRENT_TEST(ip_filter)386 TORRENT_TEST(ip_filter)
387 {
388 	torrent_state st = init_state();
389 	mock_torrent t(&st);
390 	st.allow_multiple_connections_per_ip = false;
391 	peer_list p(allocator);
392 	t.m_p = &p;
393 
394 	// add peer 1
395 	torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.2", 3000));
396 	torrent_peer* peer2 = add_peer(p, st, ep("11.0.0.2", 9020));
397 
398 	TEST_CHECK(peer1 != peer2);
399 
400 	connect_peer(p, t, st);
401 	connect_peer(p, t, st);
402 
403 	auto con1 = shared_from_this(peer1->connection);
404 	TEST_EQUAL(con1->was_disconnected(), false);
405 	auto con2 = shared_from_this(peer2->connection);
406 	TEST_EQUAL(con2->was_disconnected(), false);
407 
408 	// now, filter one of the IPs and make sure the peer is removed
409 	ip_filter filter;
410 	filter.add_rule(addr4("11.0.0.0"), addr4("255.255.255.255"), 1);
411 	std::vector<address> banned;
412 	p.apply_ip_filter(filter, &st, banned);
413 	// we just erased a peer, because it was filtered by the ip filter
414 	TEST_EQUAL(st.erased.size(), 1);
415 	TEST_EQUAL(p.num_connect_candidates(), 0);
416 	TEST_EQUAL(p.num_peers(), 1);
417 	TEST_EQUAL(banned.size(), 1);
418 	TEST_EQUAL(banned[0], addr4("11.0.0.2"));
419 	TEST_EQUAL(con2->was_disconnected(), true);
420 	TEST_EQUAL(con1->was_disconnected(), false);
421 }
422 
423 // test port filter
TORRENT_TEST(port_filter)424 TORRENT_TEST(port_filter)
425 {
426 	torrent_state st = init_state();
427 	mock_torrent t(&st);
428 	st.allow_multiple_connections_per_ip = false;
429 	peer_list p(allocator);
430 	t.m_p = &p;
431 
432 	// add peer 1
433 	torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.2", 3000));
434 	torrent_peer* peer2 = add_peer(p, st, ep("11.0.0.2", 9020));
435 
436 	TEST_CHECK(peer1 != peer2);
437 
438 	connect_peer(p, t, st);
439 	connect_peer(p, t, st);
440 
441 	auto con1 = shared_from_this(peer1->connection);
442 	TEST_EQUAL(con1->was_disconnected(), false);
443 	auto con2 = shared_from_this(peer2->connection);
444 	TEST_EQUAL(con2->was_disconnected(), false);
445 
446 	// now, filter one of the IPs and make sure the peer is removed
447 	port_filter filter;
448 	filter.add_rule(9000, 10000, 1);
449 	std::vector<address> banned;
450 	p.apply_port_filter(filter, &st, banned);
451 	// we just erased a peer, because it was filtered by the ip filter
452 	TEST_EQUAL(st.erased.size(), 1);
453 	TEST_EQUAL(p.num_connect_candidates(), 0);
454 	TEST_EQUAL(p.num_peers(), 1);
455 	TEST_EQUAL(banned.size(), 1);
456 	TEST_EQUAL(banned[0], addr4("11.0.0.2"));
457 	TEST_EQUAL(con2->was_disconnected(), true);
458 	TEST_EQUAL(con1->was_disconnected(), false);
459 }
460 
461 // test banning peers
TORRENT_TEST(ban_peers)462 TORRENT_TEST(ban_peers)
463 {
464 	torrent_state st = init_state();
465 	mock_torrent t(&st);
466 	st.allow_multiple_connections_per_ip = false;
467 	peer_list p(allocator);
468 	t.m_p = &p;
469 
470 	torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 4000));
471 
472 	TEST_EQUAL(p.num_connect_candidates(), 1);
473 	auto c = std::make_shared<mock_peer_connection>(&t, true, ep("10.0.0.1", 8080));
474 	p.new_connection(*c, 0, &st);
475 	TEST_EQUAL(p.num_connect_candidates(), 0);
476 	TEST_EQUAL(p.num_peers(), 1);
477 	st.erased.clear();
478 
479 	// now, ban the peer
480 	bool ok = p.ban_peer(c->peer_info_struct());
481 	TEST_EQUAL(ok, true);
482 	TEST_EQUAL(peer1->banned, true);
483 	// we still have it in the list
484 	TEST_EQUAL(p.num_peers(), 1);
485 	// it's just not a connect candidate, nor allowed to receive incoming connections
486 	TEST_EQUAL(p.num_connect_candidates(), 0);
487 
488 	p.connection_closed(*c, 0, &st);
489 	TEST_EQUAL(p.num_peers(), 1);
490 	TEST_EQUAL(p.num_connect_candidates(), 0);
491 	st.erased.clear();
492 
493 	c = std::make_shared<mock_peer_connection>(&t, true, ep("10.0.0.1", 8080));
494 	ok = p.new_connection(*c, 0, &st);
495 	// since it's banned, we should not allow this incoming connection
496 	TEST_EQUAL(ok, false);
497 	TEST_EQUAL(p.num_connect_candidates(), 0);
498 	st.erased.clear();
499 }
500 
501 // test erase_peers when we fill up the peer list
TORRENT_TEST(erase_peers)502 TORRENT_TEST(erase_peers)
503 {
504 	torrent_state st = init_state();
505 	mock_torrent t(&st);
506 	st.max_peerlist_size = 100;
507 	st.allow_multiple_connections_per_ip = true;
508 	peer_list p(allocator);
509 	t.m_p = &p;
510 
511 	for (int i = 0; i < 100; ++i)
512 	{
513 		TEST_EQUAL(st.erased.size(), 0);
514 		tcp::endpoint ep = rand_tcp_ep();
515 		torrent_peer* peer = add_peer(p, st, ep);
516 		TEST_CHECK(peer);
517 		if (peer == nullptr || st.erased.size() > 0)
518 		{
519 			std::printf("unexpected rejection of peer: %s | %d in list. "
520 				"added peer %p, erased %d peers\n"
521 				, print_endpoint(ep).c_str(), p.num_peers(), static_cast<void*>(peer)
522 				, int(st.erased.size()));
523 		}
524 	}
525 	TEST_EQUAL(p.num_peers(), 100);
526 
527 	// trigger the eviction of one peer
528 	torrent_peer* peer = p.add_peer(rand_tcp_ep(), {}, {}, &st);
529 	// we either removed an existing peer, or rejected this one
530 	// either is valid behavior when the list is full
531 	TEST_CHECK(st.erased.size() == 1 || peer == nullptr);
532 }
533 
534 // test set_ip_filter
TORRENT_TEST(set_ip_filter)535 TORRENT_TEST(set_ip_filter)
536 {
537 	torrent_state st = init_state();
538 	std::vector<address> banned;
539 
540 	mock_torrent t(&st);
541 	peer_list p(allocator);
542 	t.m_p = &p;
543 
544 	for (int i = 0; i < 100; ++i)
545 	{
546 		p.add_peer(tcp::endpoint(
547 			address_v4(std::uint32_t((10 << 24) + ((i + 10) << 16))), 353), {}, {}, &st);
548 		TEST_EQUAL(st.erased.size(), 0);
549 		st.erased.clear();
550 	}
551 	TEST_EQUAL(p.num_peers(), 100);
552 	TEST_EQUAL(p.num_connect_candidates(), 100);
553 
554 	// trigger the removal of one peer
555 	ip_filter filter;
556 	filter.add_rule(addr4("10.13.0.0"), addr4("10.13.255.255"), ip_filter::blocked);
557 	p.apply_ip_filter(filter, &st, banned);
558 	TEST_EQUAL(st.erased.size(), 1);
559 	TEST_EQUAL(st.erased[0]->address(), addr4("10.13.0.0"));
560 	TEST_EQUAL(p.num_peers(), 99);
561 	TEST_EQUAL(p.num_connect_candidates(), 99);
562 }
563 
564 // test set_port_filter
TORRENT_TEST(set_port_filter)565 TORRENT_TEST(set_port_filter)
566 {
567 	torrent_state st = init_state();
568 	std::vector<address> banned;
569 
570 	mock_torrent t(&st);
571 	peer_list p(allocator);
572 	t.m_p = &p;
573 
574 	for (int i = 0; i < 100; ++i)
575 	{
576 		p.add_peer(tcp::endpoint(
577 			address_v4(std::uint32_t((10 << 24) + ((i + 10) << 16))), std::uint16_t(i + 10)), {}, {}, &st);
578 		TEST_EQUAL(st.erased.size(), 0);
579 		st.erased.clear();
580 	}
581 	TEST_EQUAL(p.num_peers(), 100);
582 	TEST_EQUAL(p.num_connect_candidates(), 100);
583 
584 	// trigger the removal of one peer
585 	port_filter filter;
586 	filter.add_rule(13, 13, port_filter::blocked);
587 	p.apply_port_filter(filter, &st, banned);
588 	TEST_EQUAL(st.erased.size(), 1);
589 	TEST_EQUAL(st.erased[0]->address(), addr4("10.13.0.0"));
590 	TEST_EQUAL(st.erased[0]->port, 13);
591 	TEST_EQUAL(p.num_peers(), 99);
592 	TEST_EQUAL(p.num_connect_candidates(), 99);
593 }
594 
595 // test set_max_failcount
TORRENT_TEST(set_max_failcount)596 TORRENT_TEST(set_max_failcount)
597 {
598 	torrent_state st = init_state();
599 
600 	mock_torrent t(&st);
601 	peer_list p(allocator);
602 	t.m_p = &p;
603 
604 	for (int i = 0; i < 100; ++i)
605 	{
606 		torrent_peer* peer = p.add_peer(tcp::endpoint(
607 			address_v4(std::uint32_t((10 << 24) + ((i + 10) << 16))), std::uint16_t(i + 10)), {}, {}, &st);
608 		TEST_EQUAL(st.erased.size(), 0);
609 		st.erased.clear();
610 		// every other peer has a failcount of 1
611 		if (i % 2) p.inc_failcount(peer);
612 	}
613 	TEST_EQUAL(p.num_peers(), 100);
614 	TEST_EQUAL(p.num_connect_candidates(), 100);
615 
616 	// set the max failcount to 1 and observe how half the peers no longer
617 	// are connect candidates
618 	st.max_failcount = 1;
619 	p.set_max_failcount(&st);
620 
621 	TEST_EQUAL(p.num_connect_candidates(), 50);
622 	TEST_EQUAL(p.num_peers(), 100);
623 }
624 
625 // test set_seed
TORRENT_TEST(set_seed)626 TORRENT_TEST(set_seed)
627 {
628 	torrent_state st = init_state();
629 
630 	mock_torrent t(&st);
631 	peer_list p(allocator);
632 	t.m_p = &p;
633 
634 	for (int i = 0; i < 100; ++i)
635 	{
636 		torrent_peer* peer = p.add_peer(tcp::endpoint(
637 			address_v4(std::uint32_t((10 << 24) + ((i + 10) << 16))), std::uint16_t(i + 10)), {}, {}, &st);
638 		TEST_EQUAL(st.erased.size(), 0);
639 		st.erased.clear();
640 		// make every other peer a seed
641 		if (i % 2) p.set_seed(peer, true);
642 	}
643 	TEST_EQUAL(p.num_peers(), 100);
644 	TEST_EQUAL(p.num_connect_candidates(), 100);
645 
646 	// now, the torrent completes and we're no longer interested in
647 	// connecting to seeds. Make sure half the peers are no longer
648 	// considered connect candidates
649 	st.is_finished = true;
650 
651 	// this will make the peer_list recalculate the connect candidates
652 	std::vector<torrent_peer*> peers;
653 	p.connect_one_peer(1, &st);
654 
655 	TEST_EQUAL(p.num_connect_candidates(), 50);
656 	TEST_EQUAL(p.num_peers(), 100);
657 }
658 
659 // test has_peer
TORRENT_TEST(has_peer)660 TORRENT_TEST(has_peer)
661 {
662 	torrent_state st = init_state();
663 	std::vector<address> banned;
664 
665 	mock_torrent t(&st);
666 	peer_list p(allocator);
667 	t.m_p = &p;
668 
669 	torrent_peer* peer1 = add_peer(p, st, ep("10.10.0.1", 10));
670 	torrent_peer* peer2 = add_peer(p, st, ep("10.10.0.2", 11));
671 
672 	TEST_EQUAL(p.num_peers(), 2);
673 	TEST_EQUAL(p.num_connect_candidates(), 2);
674 
675 	TEST_EQUAL(p.has_peer(peer1), true);
676 	TEST_EQUAL(p.has_peer(peer2), true);
677 
678 	ip_filter filter;
679 	filter.add_rule(addr4("10.10.0.1"), addr4("10.10.0.1"), ip_filter::blocked);
680 	p.apply_ip_filter(filter, &st, banned);
681 	TEST_EQUAL(st.erased.size(), 1);
682 	st.erased.clear();
683 
684 	TEST_EQUAL(p.num_peers(), 1);
685 	TEST_EQUAL(p.num_connect_candidates(), 1);
686 
687 	TEST_EQUAL(p.has_peer(peer1), false);
688 	TEST_EQUAL(p.has_peer(peer2), true);
689 }
690 
691 // test connect_candidates torrent_finish
TORRENT_TEST(connect_candidates_finish)692 TORRENT_TEST(connect_candidates_finish)
693 {
694 	torrent_state st = init_state();
695 	std::vector<address> banned;
696 
697 	mock_torrent t(&st);
698 	peer_list p(allocator);
699 	t.m_p = &p;
700 
701 	torrent_peer* peer1 = add_peer(p, st, ep("10.10.0.1", 10));
702 	TEST_CHECK(peer1);
703 	p.set_seed(peer1, true);
704 	torrent_peer* peer2 = add_peer(p, st, ep("10.10.0.2", 11));
705 	TEST_CHECK(peer2);
706 	p.set_seed(peer2, true);
707 	torrent_peer* peer3 = add_peer(p, st, ep("10.10.0.3", 11));
708 	TEST_CHECK(peer3);
709 	p.set_seed(peer3, true);
710 	torrent_peer* peer4 = add_peer(p, st, ep("10.10.0.4", 11));
711 	TEST_CHECK(peer4);
712 	torrent_peer* peer5 = add_peer(p, st, ep("10.10.0.5", 11));
713 	TEST_CHECK(peer5);
714 
715 	TEST_EQUAL(p.num_peers(), 5);
716 	TEST_EQUAL(p.num_connect_candidates(), 5);
717 
718 	st.is_finished = true;
719 	// we're finished downloading now, only the non-seeds are
720 	// connect candidates
721 
722 	// connect to one of them
723 	connect_peer(p, t, st);
724 
725 	TEST_EQUAL(p.num_peers(), 5);
726 	// and there should be one left
727 	TEST_EQUAL(p.num_connect_candidates(), 1);
728 }
729 
730 // test self-connection
TORRENT_TEST(self_connection)731 TORRENT_TEST(self_connection)
732 {
733 	torrent_state st = init_state();
734 	mock_torrent t(&st);
735 	st.allow_multiple_connections_per_ip = false;
736 	peer_list p(allocator);
737 	t.m_p = &p;
738 
739 	// add and connect peer
740 	torrent_peer* peer = add_peer(p, st, ep("10.0.0.2", 3000));
741 	connect_peer(p, t, st);
742 
743 	auto con_out = shared_from_this(peer->connection);
744 	con_out->set_local_ep(ep("10.0.0.2", 8080));
745 
746 	auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 8080));
747 	con_in->set_local_ep(ep("10.0.0.2", 3000));
748 
749 	p.new_connection(*con_in, 0, &st);
750 
751 	// from the peer_list's point of view, this looks like we made one
752 	// outgoing connection and received an incoming one. Since they share
753 	// the exact same endpoints (IP ports) but just swapped source and
754 	// destination, the peer list is supposed to figure out that we connected
755 	// to ourself and disconnect it
756 	TEST_EQUAL(con_out->was_disconnected(), true);
757 	TEST_EQUAL(con_in->was_disconnected(), true);
758 }
759 
760 // test double connection (both incoming)
TORRENT_TEST(double_connection)761 TORRENT_TEST(double_connection)
762 {
763 	torrent_state st = init_state();
764 	mock_torrent t(&st);
765 	st.allow_multiple_connections_per_ip = false;
766 	peer_list p(allocator);
767 	t.m_p = &p;
768 
769 	// we are 10.0.0.1 and the other peer is 10.0.0.2
770 
771 	// first incoming connection
772 	auto con1 = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 7528));
773 	con1->set_local_ep(ep("10.0.0.1", 8080));
774 
775 	p.new_connection(*con1, 0, &st);
776 
777 	// and the incoming connection
778 	auto con2 = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 3561));
779 	con2->set_local_ep(ep("10.0.0.1", 8080));
780 
781 	p.new_connection(*con2, 0, &st);
782 
783 	// the second incoming connection should be closed
784 	TEST_EQUAL(con1->was_disconnected(), false);
785 	TEST_EQUAL(con2->was_disconnected(), true);
786 }
787 
788 // test double connection (we loose)
TORRENT_TEST(double_connection_loose)789 TORRENT_TEST(double_connection_loose)
790 {
791 	torrent_state st = init_state();
792 	mock_torrent t(&st);
793 	st.allow_multiple_connections_per_ip = false;
794 	peer_list p(allocator);
795 	t.m_p = &p;
796 
797 	// we are 10.0.0.1 and the other peer is 10.0.0.2
798 
799 	// our outgoing connection
800 	torrent_peer* peer = add_peer(p, st, ep("10.0.0.2", 3000));
801 	connect_peer(p, t, st);
802 
803 	auto con_out = shared_from_this(peer->connection);
804 	con_out->set_local_ep(ep("10.0.0.1", 3163));
805 
806 	// and the incoming connection
807 	auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 3561));
808 	con_in->set_local_ep(ep("10.0.0.1", 8080));
809 
810 	p.new_connection(*con_in, 0, &st);
811 
812 	// the rules are documented in peer_list.cpp
813 	TEST_EQUAL(con_out->was_disconnected(), true);
814 	TEST_EQUAL(con_in->was_disconnected(), false);
815 }
816 
817 // test double connection with identical ports (random)
TORRENT_TEST(double_connection_random)818 TORRENT_TEST(double_connection_random)
819 {
820 	int in = 0;
821 	int out = 0;
822 	for (int i = 0; i < 30; ++i)
823 	{
824 		torrent_state st = init_state();
825 		mock_torrent t(&st);
826 		st.allow_multiple_connections_per_ip = false;
827 		peer_list p(allocator);
828 		t.m_p = &p;
829 
830 		// we are 10.0.0.1 and the other peer is 10.0.0.2
831 
832 		// our outgoing connection
833 		torrent_peer* peer = add_peer(p, st, ep("10.0.0.2", 3000));
834 		connect_peer(p, t, st);
835 
836 		auto con_out = static_cast<mock_peer_connection*>(peer->connection)->shared_from_this();
837 		con_out->set_local_ep(ep("10.0.0.1", 3000));
838 
839 		// and the incoming connection
840 		auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 3000));
841 		con_in->set_local_ep(ep("10.0.0.1", 3000));
842 
843 		p.new_connection(*con_in, 0, &st);
844 
845 		// the rules are documented in peer_list.cpp
846 		out += con_out->was_disconnected();
847 		in += con_in->was_disconnected();
848 	}
849 	// we should have gone different ways randomly
850 	TEST_CHECK(out > 0);
851 	TEST_CHECK(in > 0);
852 }
853 
854 // test double connection (we win)
TORRENT_TEST(double_connection_win)855 TORRENT_TEST(double_connection_win)
856 {
857 	torrent_state st = init_state();
858 	mock_torrent t(&st);
859 	st.allow_multiple_connections_per_ip = false;
860 	peer_list p(allocator);
861 	t.m_p = &p;
862 
863 	// we are 10.0.0.1 and the other peer is 10.0.0.2
864 
865 	// our outgoing connection
866 	torrent_peer* peer = add_peer(p, st, ep("10.0.0.2", 8080));
867 	connect_peer(p, t, st);
868 
869 	auto con_out = shared_from_this(peer->connection);
870 	con_out->set_local_ep(ep("10.0.0.1", 3163));
871 
872 	//and the incoming connection
873 	auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 3561));
874 	con_in->set_local_ep(ep("10.0.0.1", 3000));
875 
876 	p.new_connection(*con_in, 0, &st);
877 
878 	// the rules are documented in peer_list.cpp
879 	TEST_EQUAL(con_out->was_disconnected(), false);
880 	TEST_EQUAL(con_in->was_disconnected(), true);
881 }
882 
883 // test incoming connection when we are at the list size limit
TORRENT_TEST(incoming_size_limit)884 TORRENT_TEST(incoming_size_limit)
885 {
886 	torrent_state st = init_state();
887 	st.max_peerlist_size = 5;
888 	mock_torrent t(&st);
889 	st.allow_multiple_connections_per_ip = false;
890 	peer_list p(allocator);
891 	t.m_p = &p;
892 
893 	torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 8080));
894 	TEST_CHECK(peer1);
895 	TEST_EQUAL(p.num_peers(), 1);
896 	torrent_peer* peer2 = add_peer(p, st, ep("10.0.0.2", 8080));
897 	TEST_CHECK(peer2);
898 	TEST_EQUAL(p.num_peers(), 2);
899 	torrent_peer* peer3 = add_peer(p, st, ep("10.0.0.3", 8080));
900 	TEST_CHECK(peer3);
901 	TEST_EQUAL(p.num_peers(), 3);
902 	torrent_peer* peer4 = add_peer(p, st, ep("10.0.0.4", 8080));
903 	TEST_CHECK(peer4);
904 	TEST_EQUAL(p.num_peers(), 4);
905 	torrent_peer* peer5 = add_peer(p, st, ep("10.0.0.5", 8080));
906 	TEST_CHECK(peer5);
907 	TEST_EQUAL(p.num_peers(), 5);
908 
909 	auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.1.2", 3561));
910 	con_in->set_local_ep(ep("10.0.2.1", 3000));
911 
912 	// since we're already at 5 peers in the peer list, this call should
913 	// erase one of the existing ones.
914 	p.new_connection(*con_in, 0, &st);
915 
916 	TEST_EQUAL(con_in->was_disconnected(), false);
917 	TEST_EQUAL(p.num_peers(), 5);
918 
919 	// one of the previous ones should have been removed
920 	TEST_EQUAL(has_peer(p, ep("10.0.0.1", 8080))
921 		+ has_peer(p, ep("10.0.0.2", 8080))
922 		+ has_peer(p, ep("10.0.0.3", 8080))
923 		+ has_peer(p, ep("10.0.0.4", 8080))
924 		+ has_peer(p, ep("10.0.0.5", 8080))
925 		, 4);
926 }
927 
928 // test new peer when we are at the list size limit
TORRENT_TEST(new_peer_size_limit)929 TORRENT_TEST(new_peer_size_limit)
930 {
931 	torrent_state st = init_state();
932 	st.max_peerlist_size = 5;
933 	mock_torrent t(&st);
934 	st.allow_multiple_connections_per_ip = false;
935 	peer_list p(allocator);
936 	t.m_p = &p;
937 
938 	torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 8080));
939 	TEST_CHECK(peer1);
940 	TEST_EQUAL(p.num_peers(), 1);
941 	torrent_peer* peer2 = add_peer(p, st, ep("10.0.0.2", 8080));
942 	TEST_CHECK(peer2);
943 	TEST_EQUAL(p.num_peers(), 2);
944 	torrent_peer* peer3 = add_peer(p, st, ep("10.0.0.3", 8080));
945 	TEST_CHECK(peer3);
946 	TEST_EQUAL(p.num_peers(), 3);
947 	torrent_peer* peer4 = add_peer(p, st, ep("10.0.0.4", 8080));
948 	TEST_CHECK(peer4);
949 	TEST_EQUAL(p.num_peers(), 4);
950 	torrent_peer* peer5 = add_peer(p, st, ep("10.0.0.5", 8080));
951 	TEST_CHECK(peer5);
952 	TEST_EQUAL(p.num_peers(), 5);
953 	torrent_peer* peer6 = p.add_peer(ep("10.0.0.6", 8080), {}, {}, &st);
954 	TEST_CHECK(peer6 == nullptr);
955 	TEST_EQUAL(p.num_peers(), 5);
956 
957 	// one of the connection should have been removed
958 	TEST_EQUAL(has_peer(p, ep("10.0.0.1", 8080))
959 		+ has_peer(p, ep("10.0.0.2", 8080))
960 		+ has_peer(p, ep("10.0.0.3", 8080))
961 		+ has_peer(p, ep("10.0.0.4", 8080))
962 		+ has_peer(p, ep("10.0.0.5", 8080))
963 		+ has_peer(p, ep("10.0.0.6", 8080))
964 		, 5);
965 }
966 
967 // TODO: test erasing peers
968 // TODO: test update_peer_port with allow_multiple_connections_per_ip and without
969 // TODO: test add i2p peers
970 // TODO: test allow_i2p_mixed
971 // TODO: test insert_peer failing with all error conditions
972 // TODO: test IPv6
973 // TODO: test connect_to_peer() failing
974 // TODO: test connection_closed
975 // TODO: connect candidates recalculation when incrementing failcount
976