diff --git a/test/Jamfile b/test/Jamfile index 9bc3ab46a..ae36c247e 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -33,6 +33,7 @@ project main.cpp setup_transfer.cpp dht_server.cpp + peer_server.cpp : default-build multi full diff --git a/test/dht_server.cpp b/test/dht_server.cpp index 23c062752..056d6fec7 100644 --- a/test/dht_server.cpp +++ b/test/dht_server.cpp @@ -104,7 +104,8 @@ struct dht_server udp::endpoint from; int bytes_transferred = m_socket.receive_from( asio::buffer(buffer, sizeof(buffer)), from, 0, ec); - if (ec == boost::asio::error::operation_aborted) return; + if (ec == boost::asio::error::operation_aborted + || ec == boost::asio::error::bad_descriptor) return; if (ec) { diff --git a/test/peer_server.cpp b/test/peer_server.cpp new file mode 100644 index 000000000..cff18f9ac --- /dev/null +++ b/test/peer_server.cpp @@ -0,0 +1,147 @@ +/* + +Copyright (c) 2013, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/thread.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/address.hpp" +#include "libtorrent/io_service.hpp" +#include "libtorrent/error_code.hpp" +#include "libtorrent/socket.hpp" + +#include +#include +#include + +using namespace libtorrent; + +struct peer_server +{ + + boost::asio::io_service m_ios; + boost::detail::atomic_count m_peer_requests; + tcp::acceptor m_acceptor; + int m_port; + + boost::shared_ptr m_thread; + + peer_server() + : m_peer_requests(0) + , m_acceptor(m_ios) + { + error_code ec; + m_acceptor.open(tcp::v4(), ec); + if (ec) + { + fprintf(stderr, "Error opening peer listen socket: %s\n", ec.message().c_str()); + return; + } + + m_acceptor.bind(tcp::endpoint(address_v4::any(), 0), ec); + if (ec) + { + fprintf(stderr, "Error binding peer socket to port 0: %s\n", ec.message().c_str()); + return; + } + m_port = m_acceptor.local_endpoint(ec).port(); + if (ec) + { + fprintf(stderr, "Error getting local endpoint of peer socket: %s\n", ec.message().c_str()); + return; + } + m_acceptor.listen(10, ec); + if (ec) + { + fprintf(stderr, "Error listening on peer socket: %s\n", ec.message().c_str()); + return; + } + + fprintf(stderr, "peer initialized on port %d\n", m_port); + + m_thread.reset(new thread(boost::bind(&peer_server::thread_fun, this))); + } + + ~peer_server() + { + m_acceptor.close(); + if (m_thread) m_thread->join(); + } + + int port() const { return m_port; } + + int num_hits() const { return m_peer_requests; } + + void thread_fun() + { + for (;;) + { + error_code ec; + tcp::endpoint from; + tcp::socket socket(m_ios); + m_acceptor.accept(socket, from, ec); + + if (ec == boost::asio::error::operation_aborted + || ec == boost::asio::error::bad_descriptor) return; + + if (ec) + { + fprintf(stderr, "Error accepting connection on peer socket: %s\n", ec.message().c_str()); + return; + } + + fprintf(stderr, "incoming peer connection\n"); + ++m_peer_requests; + socket.close(ec); + } + } +}; + +boost::shared_ptr g_peer; + +int start_peer() +{ + g_peer.reset(new peer_server); + return g_peer->port(); +} + +// the number of DHT messages received +int num_peer_hits() +{ + if (g_peer) return g_peer->num_hits(); + return 0; +} + +void stop_peer() +{ + g_peer.reset(); +} + diff --git a/test/peer_server.hpp b/test/peer_server.hpp new file mode 100644 index 000000000..b6d4dcc0e --- /dev/null +++ b/test/peer_server.hpp @@ -0,0 +1,40 @@ +/* + +Copyright (c) 2013, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +// returns the port the peer is running on +int start_peer(); + +// the number of incoming connections to this peer +int num_peer_hits(); + +void stop_peer(); + diff --git a/test/test_privacy.cpp b/test/test_privacy.cpp index 637907eb5..4920ae914 100644 --- a/test/test_privacy.cpp +++ b/test/test_privacy.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" #include "dht_server.hpp" +#include "peer_server.hpp" #include "libtorrent/alert.hpp" #include "libtorrent/alert_types.hpp" @@ -71,6 +72,7 @@ enum flags_t expect_http_reject = 8, expect_udp_reject = 16, expect_dht_msg = 32, + expect_peer_connection = 64, }; void test_proxy(proxy_settings::proxy_type proxy_type, int flags) @@ -79,6 +81,7 @@ void test_proxy(proxy_settings::proxy_type proxy_type, int flags) int http_port = start_web_server(); int udp_port = start_tracker(); int dht_port = start_dht(); + int peer_port = start_peer(); int prev_udp_announces = g_udp_tracker_requests; int prev_http_announces = g_http_tracker_requests; @@ -95,6 +98,11 @@ void test_proxy(proxy_settings::proxy_type proxy_type, int flags) sett.announce_to_all_tiers = true; sett.anonymous_mode = flags & anonymous_mode; sett.force_proxy = flags & anonymous_mode; + + // if we don't do this, the peer connection test + // will be delayed by several seconds, by first + // trying uTP + sett.enable_outgoing_utp = false; s->set_settings(sett); proxy_settings ps; @@ -127,7 +135,7 @@ void test_proxy(proxy_settings::proxy_type proxy_type, int flags) addp.dht_nodes.push_back(std::pair("127.0.0.1", dht_port)); torrent_handle h = s->add_torrent(addp); - //TODO: also add a peer to make sure we don't contact that as well + h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port)); rejected_trackers.clear(); for (int i = 0; i < 10; ++i) @@ -148,6 +156,15 @@ void test_proxy(proxy_settings::proxy_type proxy_type, int flags) TEST_EQUAL(num_dht_hits(), 0); } + if (flags & expect_peer_connection) + { + TEST_CHECK(num_peer_hits() > 0); + } + else + { + TEST_EQUAL(num_peer_hits(), 0); + } + if (flags & expect_udp_reject) TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end()); @@ -158,6 +175,7 @@ void test_proxy(proxy_settings::proxy_type proxy_type, int flags) delete s; fprintf(stderr, "done\n"); + stop_peer(); stop_dht(); stop_tracker(); stop_web_server(); @@ -168,7 +186,7 @@ int test_main() // not using anonymous mode // UDP fails open if we can't connect to the proxy // or if the proxy doesn't support UDP - test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg); + test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection); test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg); test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg); test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg); @@ -177,8 +195,11 @@ int test_main() test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg); // using anonymous mode - // TODO: also expect whether or not to get a anonymous_alert indicating the tracker isn't anonymous - test_proxy(proxy_settings::none, anonymous_mode); + + // anonymous mode doesn't require a proxy when one isn't configured. It could be + // used with a VPN for instance. This will all changed in 1.0, where anonymous + // mode is separated from force_proxy + test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection); test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject); test_proxy(proxy_settings::socks5, anonymous_mode); test_proxy(proxy_settings::socks5_pw, anonymous_mode);