From a577dac775490d4df0fd612dc3f994529dadf198 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 29 Sep 2013 22:50:06 +0000 Subject: [PATCH] split up test_web_seed into smaller tests --- test/Jamfile | 7 + test/http.py | 2 +- test/setup_transfer.cpp | 26 ++- test/setup_transfer.hpp | 1 + test/socks.py | 3 +- test/test_web_seed.cpp | 319 +---------------------------- test/test_web_seed_http.cpp | 59 ++++++ test/test_web_seed_http_pw.cpp | 59 ++++++ test/test_web_seed_socks4.cpp | 59 ++++++ test/test_web_seed_socks5.cpp | 59 ++++++ test/test_web_seed_socks5_pw.cpp | 59 ++++++ test/web_seed_suite.cpp | 332 +++++++++++++++++++++++++++++++ test/web_seed_suite.hpp | 35 ++++ 13 files changed, 700 insertions(+), 320 deletions(-) create mode 100644 test/test_web_seed_http.cpp create mode 100644 test/test_web_seed_http_pw.cpp create mode 100644 test/test_web_seed_socks4.cpp create mode 100644 test/test_web_seed_socks5.cpp create mode 100644 test/test_web_seed_socks5_pw.cpp create mode 100644 test/web_seed_suite.cpp create mode 100644 test/web_seed_suite.hpp diff --git a/test/Jamfile b/test/Jamfile index be63738b3..6e02f098b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -63,6 +63,7 @@ lib libtorrent_test dht_server.cpp peer_server.cpp ../ed25519/src/$(ED25519_SOURCES).c + web_seed_suite.cpp : # requirements # this is used to determine whether @@ -127,6 +128,12 @@ test-suite libtorrent : [ run test_tracker.cpp ] [ run test_checking.cpp ] [ run test_web_seed.cpp ] + [ run test_web_seed_socks4.cpp ] + [ run test_web_seed_socks5.cpp ] + [ run test_web_seed_socks5_pw.cpp ] + [ run test_web_seed_http.cpp ] + [ run test_web_seed_http_pw.cpp ] + [ run test_web_seed.cpp ] [ run test_bdecode_performance.cpp ] [ run test_pe_crypto.cpp ] diff --git a/test/http.py b/test/http.py index b9b0ce479..2f158715d 100644 --- a/test/http.py +++ b/test/http.py @@ -192,8 +192,8 @@ def start_server(host='localhost', port=8080, IPv6=False, timeout=60, else: soc_type=socket.AF_INET soc = socket.socket(soc_type) - soc.bind((host, port)) print "Serving on %s:%d."%(host, port)#debug + soc.bind((host, port)) soc.listen(0) while 1: thread.start_new_thread(handler, soc.accept()+(timeout,)) diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index dbb93be10..af0bc714f 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -178,6 +178,27 @@ int load_file(std::string const& filename, std::vector& v, libtorrent::err return 0; } +void save_file(char const* filename, char const* data, int size) +{ + error_code ec; + file out(filename, file::write_only, ec); + TEST_CHECK(!ec); + if (ec) + { + fprintf(stderr, "ERROR opening file '%s': %s\n", filename, ec.message().c_str()); + return; + } + file::iovec_t b = { (void*)data, size_t(size) }; + out.writev(0, &b, 1, ec); + TEST_CHECK(!ec); + if (ec) + { + fprintf(stderr, "ERROR writing file '%s': %s\n", filename, ec.message().c_str()); + return; + } + +} + bool print_alerts(libtorrent::session& ses, char const* name , bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume , bool (*predicate)(libtorrent::alert*), bool no_output) @@ -385,8 +406,8 @@ int start_proxy(int proxy_type) { using namespace libtorrent; - static int port = 5000 + (rand() % 55000); - ++port; + std::srand((unsigned int)total_microseconds(time_now() - min_time())); + int port = 5000 + (rand() % 55000); for (std::map::iterator i = running_proxies.begin() , end(running_proxies.end()); i != end; ++i) @@ -586,7 +607,6 @@ setup_transfer(session* ses1, session* ses2, session* ses3 ses2->set_alert_mask(~(alert::progress_notification | alert::stats_notification)); if (ses3) ses3->set_alert_mask(~(alert::progress_notification | alert::stats_notification)); - std::srand((unsigned int)time(0)); peer_id pid; std::generate(&pid[0], &pid[0] + 20, std::rand); ses1->set_peer_id(pid); diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 2130da85e..949917445 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -47,6 +47,7 @@ namespace libtorrent int EXPORT print_failures(); int EXPORT load_file(std::string const& filename, std::vector& v, libtorrent::error_code& ec, int limit = 8000000); +void EXPORT save_file(char const* filename, char const* data, int size); void EXPORT report_failure(char const* err, char const* file, int line); diff --git a/test/socks.py b/test/socks.py index 3ad2e67ea..43602c7b5 100644 --- a/test/socks.py +++ b/test/socks.py @@ -32,7 +32,8 @@ allow_v4 = False def send(dest, msg): if msg == CLOSE: - dest.shutdown(socket.SHUT_WR) + try: dest.shutdown(socket.SHUT_WR) + except: pass dest.close() return 0 else: diff --git a/test/test_web_seed.cpp b/test/test_web_seed.cpp index 31aee3f9b..9c07fa17c 100644 --- a/test/test_web_seed.cpp +++ b/test/test_web_seed.cpp @@ -30,324 +30,13 @@ POSSIBILITY OF SUCH DAMAGE. */ -#include "libtorrent/session.hpp" -#include "libtorrent/hasher.hpp" -#include "libtorrent/file_pool.hpp" -#include "libtorrent/storage.hpp" -#include "libtorrent/bencode.hpp" -#include "libtorrent/create_torrent.hpp" -#include "libtorrent/thread.hpp" -#include "libtorrent/alert_types.hpp" -#include -#include -#include - #include "test.hpp" #include "setup_transfer.hpp" +#include "web_seed_suite.hpp" using namespace libtorrent; -int peer_disconnects = 0; - -bool on_alert(alert* a) -{ - if (alert_cast(a)) - ++peer_disconnects; - else if (alert_cast(a)) - ++peer_disconnects; - - return false; -} - -// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw -void test_transfer(session& ses, boost::intrusive_ptr torrent_file - , int proxy, int port, char const* protocol, bool url_seed, bool chunked_encoding, bool test_ban) -{ - using namespace libtorrent; - - error_code ec; - remove_all("tmp2_web_seed", ec); - - char const* test_name[] = {"no", "SOCKS4", "SOCKS5", "SOCKS5 password", "HTTP", "HTTP password"}; - - fprintf(stderr, "\n\n ==== TESTING === proxy: %s ==== protocol: %s ==== seed: %s === transfer-encoding: %s === corruption: %s\n\n\n" - , test_name[proxy], protocol, url_seed ? "URL seed" : "HTTP seed", chunked_encoding ? "chunked": "none", test_ban ? "yes" : "no"); - - proxy_settings ps; - - if (proxy) - { - ps.port = start_proxy(proxy); - ps.hostname = "127.0.0.1"; - ps.username = "testuser"; - ps.password = "testpass"; - ps.type = (proxy_settings::proxy_type)proxy; - ses.set_proxy(ps); - } - - add_torrent_params p; - p.flags &= ~add_torrent_params::flag_paused; - p.flags &= ~add_torrent_params::flag_auto_managed; - p.ti = torrent_file; - p.save_path = "tmp2_web_seed"; -#ifndef TORRENT_NO_DEPRECATE - p.storage_mode = storage_mode_compact; -#endif - torrent_handle th = ses.add_torrent(p, ec); - - std::vector empty; - th.replace_trackers(empty); - - const size_type total_size = torrent_file->total_size(); - - float rate_sum = 0.f; - float ses_rate_sum = 0.f; - - cache_status cs; - - file_storage const& fs = torrent_file->files(); - int pad_file_size = 0; - for (int i = 0; i < fs.num_files(); ++i) - { - file_entry f = fs.at(i); - if (f.pad_file) pad_file_size += f.size; - } - - peer_disconnects = 0; - - for (int i = 0; i < 40; ++i) - { - torrent_status s = th.status(); - session_status ss = ses.status(); - rate_sum += s.download_payload_rate; - ses_rate_sum += ss.payload_download_rate; - - cs = ses.get_cache_status(); - if (cs.blocks_read < 1) cs.blocks_read = 1; - if (cs.blocks_written < 1) cs.blocks_written = 1; - - print_ses_rate(i / 10.f, &s, NULL); - - print_alerts(ses, " >> ses", test_ban, false, false, &on_alert); - - if (test_ban && th.url_seeds().empty() && th.http_seeds().empty()) - { - // when we don't have any web seeds left, we know we successfully banned it - break; - } - -// if (test_ban && peer_disconnects >= 1) break; - - if (s.is_seeding /* && ss.download_rate == 0.f*/) - { - TEST_EQUAL(s.total_payload_download - s.total_redundant_bytes, total_size - pad_file_size); - // we need to sleep here a bit to let the session sync with the torrent stats - // commented out because it takes such a long time -// test_sleep(1000); -// TEST_EQUAL(ses.status().total_payload_download - ses.status().total_redundant_bytes -// , total_size - pad_file_size); - break; - } - test_sleep(100); - } - - // for test_ban tests, make sure we removed - // the url seed (i.e. banned it) - TEST_CHECK(!test_ban || (th.url_seeds().empty() && th.http_seeds().empty())); - - TEST_EQUAL(cs.cache_size, 0); - TEST_EQUAL(cs.total_used_buffers, 0); - - std::cerr << "total_size: " << total_size - << " rate_sum: " << rate_sum - << " session_rate_sum: " << ses_rate_sum - << " session total download: " << ses.status().total_payload_download - << " torrent total download: " << th.status().total_payload_download - << " redundant: " << th.status().total_redundant_bytes - << std::endl; - - // the rates for each second should sum up to the total, with a 10% error margin -// TEST_CHECK(fabs(rate_sum - total_size) < total_size * .1f); -// TEST_CHECK(fabs(ses_rate_sum - total_size) < total_size * .1f); - - // if test_ban is true, we're not supposed to have completed the download - // otherwise, we are supposed to have - TEST_CHECK(th.status().is_seeding == !test_ban); - - if (proxy) stop_proxy(ps.port); - - ses.remove_torrent(th); - - // call this to synchronize with the network thread - ses.status(); - - print_alerts(ses, " >> ses", true, true, false, &on_alert, true); - - TEST_CHECK(exists(combine_path("tmp2_web_seed", torrent_file->files().file_path(0))) || test_ban); - remove_all("tmp2_web_seed", ec); -} - -void save_file(char const* filename, char const* data, int size) -{ - error_code ec; - file out(filename, file::write_only, ec); - TEST_CHECK(!ec); - if (ec) - { - fprintf(stderr, "ERROR opening file '%s': %s\n", filename, ec.message().c_str()); - return; - } - file::iovec_t b = { (void*)data, size_t(size) }; - out.writev(0, &b, 1, ec); - TEST_CHECK(!ec); - if (ec) - { - fprintf(stderr, "ERROR writing file '%s': %s\n", filename, ec.message().c_str()); - return; - } - -} - -sha1_hash file_hash(std::string const& name) -{ - std::vector buf; - error_code ec; - load_file(name, buf, ec); - if (buf.empty()) return sha1_hash(0); - hasher h(&buf[0], buf.size()); - return h.final(); -} - -const int num_pieces = 9; - -// test_url_seed determines whether to use url-seed or http-seed -int run_suite(char const* protocol, bool test_url_seed, bool chunked_encoding, bool test_ban) -{ - using namespace libtorrent; - - error_code ec; - create_directories("tmp1_web_seed/test_torrent_dir", ec); - - file_storage fs; - std::srand(10); - int piece_size = 0x4000; - static const int file_sizes[] = - { 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 - ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; - - if (test_url_seed) - { - create_random_files("tmp1_web_seed/test_torrent_dir", file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); - add_files(fs, "tmp1_web_seed/test_torrent_dir"); - } - else - { - piece_size = 64 * 1024; - char* random_data = (char*)malloc(64 * 1024 * num_pieces); - std::generate(random_data, random_data + 64 * 1024 * num_pieces, &std::rand); - save_file("tmp1_web_seed/seed", random_data, 64 * 1024 * num_pieces); - fs.add_file("seed", 64 * 1024 * num_pieces); - free(random_data); - } - - int port = start_web_server(strcmp(protocol, "https") == 0, chunked_encoding); - - // generate a torrent with pad files to make sure they - // are not requested web seeds - libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize - | libtorrent::create_torrent::calculate_file_hashes); - - char tmp[512]; - if (test_url_seed) - { - snprintf(tmp, sizeof(tmp), "%s://127.0.0.1:%d/tmp1_web_seed", protocol, port); - t.add_url_seed(tmp); - } - else - { - snprintf(tmp, sizeof(tmp), "%s://127.0.0.1:%d/seed", protocol, port); - t.add_http_seed(tmp); - } - fprintf(stderr, "testing: %s\n", tmp); - - for (int i = 0; i < fs.num_files(); ++i) - { - file_entry f = fs.at(i); - fprintf(stderr, " %04x: %d %s\n", int(f.offset), f.pad_file, f.path.c_str()); - } - - // calculate the hash for all pieces - set_piece_hashes(t, "tmp1_web_seed", ec); - - if (ec) - { - fprintf(stderr, "error creating hashes for test torrent: %s\n" - , ec.message().c_str()); - TEST_CHECK(false); - return 0; - } - - if (test_ban) - { - // corrupt the files now, so that the web seed will be banned - if (test_url_seed) - { - create_random_files("tmp1_web_seed/test_torrent_dir", file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); - } - else - { - piece_size = 64 * 1024; - char* random_data = (char*)malloc(64 * 1024 * num_pieces); - std::generate(random_data, random_data + 64 * 1024 * num_pieces, &std::rand); - save_file("tmp1_web_seed/seed", random_data, 64 * 1024 * num_pieces); - free(random_data); - } - } - - std::vector buf; - bencode(std::back_inserter(buf), t.generate()); - boost::intrusive_ptr torrent_file(new torrent_info(&buf[0], buf.size(), ec)); - - // no point in testing the hashes since we know the data is corrupt - if (!test_ban) - { - // verify that the file hashes are correct - for (int i = 0; i < torrent_file->num_files(); ++i) - { - sha1_hash h1 = torrent_file->file_at(i).filehash; - sha1_hash h2 = file_hash(combine_path("tmp1_web_seed" - , torrent_file->file_at(i).path)); -// fprintf(stderr, "%s: %s == %s\n" -// , torrent_file->file_at(i).path.c_str() -// , to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str()); - TEST_EQUAL(h1, h2); - } - } - - { - session ses(fingerprint(" ", 0,0,0,0), 0); - session_settings settings; - settings.max_queued_disk_bytes = 256 * 1024; - ses.set_settings(settings); - ses.set_alert_mask(~(alert::progress_notification | alert::stats_notification)); - error_code ec; - ses.listen_on(std::make_pair(51000, 52000), ec); - if (ec) fprintf(stderr, "listen_on failed: %s\n", ec.message().c_str()); - - for (int i = 0; i < 6; ++i) - test_transfer(ses, torrent_file, i, port, protocol, test_url_seed, chunked_encoding, test_ban); - - if (test_url_seed) - { - torrent_file->rename_file(0, "tmp2_web_seed/test_torrent_dir/renamed_test1"); - test_transfer(ses, torrent_file, 0, port, protocol, test_url_seed, chunked_encoding, test_ban); - } - } - - stop_web_server(); - remove_all("tmp1_web_seed", ec); - return 0; -} +const int proxy = libtorrent::proxy_settings::none; int test_main() { @@ -359,9 +48,9 @@ int test_main() for (int ban = 0; ban < 2; ++ban) { #ifdef TORRENT_USE_OPENSSL - run_suite("https", url_seed, chunked, ban); + run_http_suite(proxy, "https", url_seed, chunked, ban); #endif - run_suite("http", url_seed, chunked, ban); + run_http_suite(proxy, "http", url_seed, chunked, ban); } } } diff --git a/test/test_web_seed_http.cpp b/test/test_web_seed_http.cpp new file mode 100644 index 000000000..df42bb6eb --- /dev/null +++ b/test/test_web_seed_http.cpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "web_seed_suite.hpp" + +using namespace libtorrent; + +const int proxy = libtorrent::proxy_settings::http; + +int test_main() +{ + int ret = 0; + for (int url_seed = 0; url_seed < 2; ++url_seed) + { + for (int chunked = 0; chunked < 2; ++chunked) + { + for (int ban = 0; ban < 2; ++ban) + { +#ifdef TORRENT_USE_OPENSSL + run_http_suite(proxy, "https", url_seed, chunked, ban); +#endif + run_http_suite(proxy, "http", url_seed, chunked, ban); + } + } + } + return ret; +} + diff --git a/test/test_web_seed_http_pw.cpp b/test/test_web_seed_http_pw.cpp new file mode 100644 index 000000000..389c39a88 --- /dev/null +++ b/test/test_web_seed_http_pw.cpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "web_seed_suite.hpp" + +using namespace libtorrent; + +const int proxy = libtorrent::proxy_settings::http_pw; + +int test_main() +{ + int ret = 0; + for (int url_seed = 0; url_seed < 2; ++url_seed) + { + for (int chunked = 0; chunked < 2; ++chunked) + { + for (int ban = 0; ban < 2; ++ban) + { +#ifdef TORRENT_USE_OPENSSL + run_http_suite(proxy, "https", url_seed, chunked, ban); +#endif + run_http_suite(proxy, "http", url_seed, chunked, ban); + } + } + } + return ret; +} + diff --git a/test/test_web_seed_socks4.cpp b/test/test_web_seed_socks4.cpp new file mode 100644 index 000000000..0e008411f --- /dev/null +++ b/test/test_web_seed_socks4.cpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "web_seed_suite.hpp" + +using namespace libtorrent; + +const int proxy = libtorrent::proxy_settings::socks4; + +int test_main() +{ + int ret = 0; + for (int url_seed = 0; url_seed < 2; ++url_seed) + { + for (int chunked = 0; chunked < 2; ++chunked) + { + for (int ban = 0; ban < 2; ++ban) + { +#ifdef TORRENT_USE_OPENSSL + run_http_suite(proxy, "https", url_seed, chunked, ban); +#endif + run_http_suite(proxy, "http", url_seed, chunked, ban); + } + } + } + return ret; +} + diff --git a/test/test_web_seed_socks5.cpp b/test/test_web_seed_socks5.cpp new file mode 100644 index 000000000..f4181b197 --- /dev/null +++ b/test/test_web_seed_socks5.cpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "web_seed_suite.hpp" + +using namespace libtorrent; + +const int proxy = libtorrent::proxy_settings::socks5; + +int test_main() +{ + int ret = 0; + for (int url_seed = 0; url_seed < 2; ++url_seed) + { + for (int chunked = 0; chunked < 2; ++chunked) + { + for (int ban = 0; ban < 2; ++ban) + { +#ifdef TORRENT_USE_OPENSSL + run_http_suite(proxy, "https", url_seed, chunked, ban); +#endif + run_http_suite(proxy, "http", url_seed, chunked, ban); + } + } + } + return ret; +} + diff --git a/test/test_web_seed_socks5_pw.cpp b/test/test_web_seed_socks5_pw.cpp new file mode 100644 index 000000000..d29e73ce4 --- /dev/null +++ b/test/test_web_seed_socks5_pw.cpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "web_seed_suite.hpp" + +using namespace libtorrent; + +const int proxy = libtorrent::proxy_settings::socks5_pw; + +int test_main() +{ + int ret = 0; + for (int url_seed = 0; url_seed < 2; ++url_seed) + { + for (int chunked = 0; chunked < 2; ++chunked) + { + for (int ban = 0; ban < 2; ++ban) + { +#ifdef TORRENT_USE_OPENSSL + run_http_suite(proxy, "https", url_seed, chunked, ban); +#endif + run_http_suite(proxy, "http", url_seed, chunked, ban); + } + } + } + return ret; +} + diff --git a/test/web_seed_suite.cpp b/test/web_seed_suite.cpp new file mode 100644 index 000000000..315003d3c --- /dev/null +++ b/test/web_seed_suite.cpp @@ -0,0 +1,332 @@ +/* + +Copyright (c) 2008-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 "setup_transfer.hpp" +#include "libtorrent/alert_types.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/create_torrent.hpp" +#include "libtorrent/thread.hpp" +#include "libtorrent/alert_types.hpp" +#include + +#include + +using namespace libtorrent; + +int peer_disconnects = 0; + +bool on_alert(alert* a) +{ + if (alert_cast(a)) + ++peer_disconnects; + else if (alert_cast(a)) + ++peer_disconnects; + + return false; +} + +const int num_pieces = 9; + +static sha1_hash file_hash(std::string const& name) +{ + std::vector buf; + error_code ec; + load_file(name, buf, ec); + if (buf.empty()) return sha1_hash(0); + hasher h(&buf[0], buf.size()); + return h.final(); +} + +// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw +static void test_transfer(session& ses, boost::intrusive_ptr torrent_file + , int proxy, int port, char const* protocol, bool url_seed, bool chunked_encoding, bool test_ban) +{ + using namespace libtorrent; + + error_code ec; + remove_all("tmp2_web_seed", ec); + + char const* test_name[] = {"no", "SOCKS4", "SOCKS5", "SOCKS5 password", "HTTP", "HTTP password"}; + + fprintf(stderr, "\n\n ==== TESTING === proxy: %s ==== protocol: %s ==== seed: %s === transfer-encoding: %s === corruption: %s\n\n\n" + , test_name[proxy], protocol, url_seed ? "URL seed" : "HTTP seed", chunked_encoding ? "chunked": "none", test_ban ? "yes" : "no"); + + proxy_settings ps; + + if (proxy) + { + ps.port = start_proxy(proxy); + ps.hostname = "127.0.0.1"; + ps.username = "testuser"; + ps.password = "testpass"; + ps.type = (proxy_settings::proxy_type)proxy; + ses.set_proxy(ps); + } + + add_torrent_params p; + p.flags &= ~add_torrent_params::flag_paused; + p.flags &= ~add_torrent_params::flag_auto_managed; + p.ti = torrent_file; + p.save_path = "tmp2_web_seed"; +#ifndef TORRENT_NO_DEPRECATE + p.storage_mode = storage_mode_compact; +#endif + torrent_handle th = ses.add_torrent(p, ec); + + std::vector empty; + th.replace_trackers(empty); + + const size_type total_size = torrent_file->total_size(); + + float rate_sum = 0.f; + float ses_rate_sum = 0.f; + + cache_status cs; + + file_storage const& fs = torrent_file->files(); + int pad_file_size = 0; + for (int i = 0; i < fs.num_files(); ++i) + { + file_entry f = fs.at(i); + if (f.pad_file) pad_file_size += f.size; + } + + peer_disconnects = 0; + + for (int i = 0; i < 40; ++i) + { + torrent_status s = th.status(); + session_status ss = ses.status(); + rate_sum += s.download_payload_rate; + ses_rate_sum += ss.payload_download_rate; + + cs = ses.get_cache_status(); + if (cs.blocks_read < 1) cs.blocks_read = 1; + if (cs.blocks_written < 1) cs.blocks_written = 1; + + print_ses_rate(i / 10.f, &s, NULL); + + print_alerts(ses, " >> ses", test_ban, false, false, &on_alert); + + if (test_ban && th.url_seeds().empty() && th.http_seeds().empty()) + { + // when we don't have any web seeds left, we know we successfully banned it + break; + } + +// if (test_ban && peer_disconnects >= 1) break; + + if (s.is_seeding /* && ss.download_rate == 0.f*/) + { + TEST_EQUAL(s.total_payload_download - s.total_redundant_bytes, total_size - pad_file_size); + break; + } + test_sleep(100); + } + + // for test_ban tests, make sure we removed + // the url seed (i.e. banned it) + TEST_CHECK(!test_ban || (th.url_seeds().empty() && th.http_seeds().empty())); + + TEST_EQUAL(cs.cache_size, 0); + TEST_EQUAL(cs.total_used_buffers, 0); + + std::cerr << "total_size: " << total_size + << " rate_sum: " << rate_sum + << " session_rate_sum: " << ses_rate_sum + << " session total download: " << ses.status().total_payload_download + << " torrent total download: " << th.status().total_payload_download + << " redundant: " << th.status().total_redundant_bytes + << std::endl; + + // the rates for each second should sum up to the total, with a 10% error margin +// TEST_CHECK(fabs(rate_sum - total_size) < total_size * .1f); +// TEST_CHECK(fabs(ses_rate_sum - total_size) < total_size * .1f); + + // if test_ban is true, we're not supposed to have completed the download + // otherwise, we are supposed to have + TEST_CHECK(th.status().is_seeding == !test_ban); + + if (proxy) stop_proxy(ps.port); + + ses.remove_torrent(th); + + // call this to synchronize with the network thread + ses.status(); + + print_alerts(ses, " >> ses", true, true, false, &on_alert, true); + + TEST_CHECK(exists(combine_path("tmp2_web_seed", torrent_file->files().file_path(0))) || test_ban); + remove_all("tmp2_web_seed", ec); +} + +// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw +// protocol: "http" or "https" +// test_url_seed determines whether to use url-seed or http-seed +int run_http_suite(int proxy, char const* protocol, bool test_url_seed, bool chunked_encoding, bool test_ban) +{ + using namespace libtorrent; + + error_code ec; + create_directories("tmp1_web_seed/test_torrent_dir", ec); + if (ec) + { + fprintf(stderr, "FAILED TO CREATE DIRECTORY: (%d) %s\n" + , ec.value(), ec.message().c_str()); + TEST_CHECK(!ec); + return 1; + } + + file_storage fs; + std::srand(10); + int piece_size = 0x4000; + static const int file_sizes[] = + { 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 + ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; + + if (test_url_seed) + { + create_random_files("tmp1_web_seed/test_torrent_dir", file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); + add_files(fs, "tmp1_web_seed/test_torrent_dir"); + } + else + { + piece_size = 64 * 1024; + char* random_data = (char*)malloc(64 * 1024 * num_pieces); + std::generate(random_data, random_data + 64 * 1024 * num_pieces, &std::rand); + save_file("tmp1_web_seed/seed", random_data, 64 * 1024 * num_pieces); + fs.add_file("seed", 64 * 1024 * num_pieces); + free(random_data); + } + + int port = start_web_server(strcmp(protocol, "https") == 0, chunked_encoding); + + // generate a torrent with pad files to make sure they + // are not requested web seeds + libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize + | libtorrent::create_torrent::calculate_file_hashes); + + char tmp[512]; + if (test_url_seed) + { + snprintf(tmp, sizeof(tmp), "%s://127.0.0.1:%d/tmp1_web_seed", protocol, port); + t.add_url_seed(tmp); + } + else + { + snprintf(tmp, sizeof(tmp), "%s://127.0.0.1:%d/seed", protocol, port); + t.add_http_seed(tmp); + } + fprintf(stderr, "testing: %s\n", tmp); + + for (int i = 0; i < fs.num_files(); ++i) + { + file_entry f = fs.at(i); + fprintf(stderr, " %04x: %d %s\n", int(f.offset), f.pad_file, f.path.c_str()); + } + + // calculate the hash for all pieces + set_piece_hashes(t, "tmp1_web_seed", ec); + + if (ec) + { + fprintf(stderr, "error creating hashes for test torrent: %s\n" + , ec.message().c_str()); + TEST_CHECK(false); + return 0; + } + + if (test_ban) + { + // corrupt the files now, so that the web seed will be banned + if (test_url_seed) + { + create_random_files("tmp1_web_seed/test_torrent_dir", file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); + } + else + { + piece_size = 64 * 1024; + char* random_data = (char*)malloc(64 * 1024 * num_pieces); + std::generate(random_data, random_data + 64 * 1024 * num_pieces, &std::rand); + save_file("tmp1_web_seed/seed", random_data, 64 * 1024 * num_pieces); + free(random_data); + } + } + + std::vector buf; + bencode(std::back_inserter(buf), t.generate()); + boost::intrusive_ptr torrent_file(new torrent_info(&buf[0], buf.size(), ec)); + + // no point in testing the hashes since we know the data is corrupt + if (!test_ban) + { + // verify that the file hashes are correct + for (int i = 0; i < torrent_file->num_files(); ++i) + { + sha1_hash h1 = torrent_file->file_at(i).filehash; + sha1_hash h2 = file_hash(combine_path("tmp1_web_seed" + , torrent_file->file_at(i).path)); +// fprintf(stderr, "%s: %s == %s\n" +// , torrent_file->file_at(i).path.c_str() +// , to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str()); + TEST_EQUAL(h1, h2); + } + } + + { + session ses(fingerprint(" ", 0,0,0,0), 0); + session_settings settings; + settings.max_queued_disk_bytes = 256 * 1024; + ses.set_settings(settings); + ses.set_alert_mask(~(alert::progress_notification | alert::stats_notification)); + error_code ec; + ses.listen_on(std::make_pair(51000, 52000), ec); + if (ec) fprintf(stderr, "listen_on failed: %s\n", ec.message().c_str()); + + test_transfer(ses, torrent_file, proxy, port, protocol, test_url_seed, chunked_encoding, test_ban); + + if (test_url_seed) + { + torrent_file->rename_file(0, "tmp2_web_seed/test_torrent_dir/renamed_test1"); + test_transfer(ses, torrent_file, 0, port, protocol, test_url_seed, chunked_encoding, test_ban); + } + } + + stop_web_server(); + remove_all("tmp1_web_seed", ec); + return 0; +} + + diff --git a/test/web_seed_suite.hpp b/test/web_seed_suite.hpp new file mode 100644 index 000000000..4df43ea65 --- /dev/null +++ b/test/web_seed_suite.hpp @@ -0,0 +1,35 @@ +/* + +Copyright (c) 2008-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 "test.hpp" + +EXPORT int run_http_suite(int proxy, char const* protocol, bool test_url_seed, bool chunked_encoding, bool test_ban); +