diff options
author | Allen Zhong | 2024-03-26 00:18:40 +0900 |
---|---|---|
committer | Allen Zhong | 2024-03-26 00:18:40 +0900 |
commit | a1108a1c0a24447e16deb2a1e387bce066cf828e (patch) | |
tree | 84206e080053e4d3a9b8ef365bbbbde1547d566b | |
parent | 9efc5dcc5691b80c90349b9aa6ef99a3a7be5cbf (diff) | |
download | aur-libtorrent-ipv6.tar.gz |
apply patch from track-ipv6 branch
-rw-r--r-- | .SRCINFO | 8 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | PKGBUILD | 11 | ||||
-rw-r--r-- | tracker-ipv6.patch | 3733 |
4 files changed, 3746 insertions, 7 deletions
@@ -2,7 +2,7 @@ pkgbase = libtorrent-ipv6 pkgdesc = BitTorrent library with a focus on high performance and good code, with ipv6 support pkgver = 0.13.8 pkgrel = 4 - url = http://rakshasa.github.io/rtorrent/ + url = https://github.com/rakshasa/libtorrent arch = x86_64 license = GPL makedepends = git @@ -10,7 +10,9 @@ pkgbase = libtorrent-ipv6 depends = zlib provides = libtorrent conflicts = libtorrent - source = libtorrent::git+https://github.com/rakshasa/libtorrent.git#commit=ac8d6d1be5341e8dfa4ac33fef0bf8940a00c8f3 - sha256sums = SKIP + source = libtorrent::git+https://github.com/rakshasa/libtorrent.git#commit=91f8cf4b0358d9b4480079ca7798fa7d9aec76b5 + source = tracker-ipv6.patch + sha256sums = a5dcc71582ab775981cb9133bf07392926f482843972c8874743f92f7f305851 + sha256sums = c0b08f7dec58136ed705c46a07fcd10b1c2b828462486b7e1df25c499b910a15 pkgname = libtorrent-ipv6 diff --git a/.gitignore b/.gitignore index 7e9650beff95..36b42ce89c39 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ cookies *.log libtorrent/ +tmp/ @@ -1,5 +1,5 @@ # $Id$ -# Maintainer: Allen Zhong <moeallenz@gmail.com> +# Maintainer: Allen Zhong <pdev@zhoal.pw> # Contributor: Gaetan Bisson <bisson@archlinux.org> # Contributor: Jaroslav Lichtblau <svetlemodry@archlinux.org> # Contributor: Daenyth <Daenyth+Arch [at] gmail [dot] com> @@ -11,18 +11,21 @@ pkgname=libtorrent-ipv6 pkgver=0.13.8 pkgrel=4 pkgdesc='BitTorrent library with a focus on high performance and good code, with ipv6 support' -url='http://rakshasa.github.io/rtorrent/' +url='https://github.com/rakshasa/libtorrent' arch=('x86_64') license=('GPL') depends=('openssl' 'zlib') makedepends=('git') conflicts=("${_pkgname}") provides=("${_pkgname}") -source=("$_pkgname::git+https://github.com/rakshasa/libtorrent.git#commit=ac8d6d1be5341e8dfa4ac33fef0bf8940a00c8f3") -sha256sums=('SKIP') +source=("$_pkgname::git+https://github.com/rakshasa/libtorrent.git#commit=91f8cf4b0358d9b4480079ca7798fa7d9aec76b5" + tracker-ipv6.patch) +sha256sums=('a5dcc71582ab775981cb9133bf07392926f482843972c8874743f92f7f305851' + 'c0b08f7dec58136ed705c46a07fcd10b1c2b828462486b7e1df25c499b910a15') prepare() { cd "${srcdir}/${_pkgname}" + patch -Np1 -i ../tracker-ipv6.patch sed '/AM_PATH_CPPUNIT/d' -i configure.ac aclocal -I ./scripts -I . autoheader diff --git a/tracker-ipv6.patch b/tracker-ipv6.patch new file mode 100644 index 000000000000..10fc109382d9 --- /dev/null +++ b/tracker-ipv6.patch @@ -0,0 +1,3733 @@ +diff --git a/configure.ac b/configure.ac +index 453e2936..e9f3b816 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -111,10 +111,10 @@ CC_ATTRIBUTE_UNUSED( + ) + + AC_CONFIG_FILES([ +- libtorrent.pc +- Makefile +- src/Makefile +- src/torrent/Makefile ++ libtorrent.pc ++ Makefile ++ src/Makefile ++ src/torrent/Makefile + test/Makefile + test/torrent/net/Makefile + test/net/Makefile +diff --git a/scripts/ax_cxx_compile_stdcxx.m4 b/scripts/ax_cxx_compile_stdcxx.m4 +old mode 100755 +new mode 100644 +diff --git a/src/download/download_main.cc b/src/download/download_main.cc +index e075038a..7541fb6d 100644 +--- a/src/download/download_main.cc ++++ b/src/download/download_main.cc +@@ -66,7 +66,7 @@ DownloadMain::DownloadMain() : + m_uploadThrottle(NULL), + m_downloadThrottle(NULL) { + +- m_tracker_list = new TrackerList(); ++ m_tracker_list = new TrackerList(m_info); + m_tracker_controller = new TrackerController(m_tracker_list); + + m_tracker_list->slot_success() = std::bind(&TrackerController::receive_success, m_tracker_controller, std::placeholders::_1, std::placeholders::_2); +diff --git a/src/download/download_wrapper.cc b/src/download/download_wrapper.cc +index 304bddce..3fb45588 100644 +--- a/src/download/download_wrapper.cc ++++ b/src/download/download_wrapper.cc +@@ -45,7 +45,6 @@ DownloadWrapper::DownloadWrapper() : + m_main->delay_partially_restarted().slot() = std::bind(&download_data::call_partially_restarted, data()); + + m_main->peer_list()->set_info(info()); +- m_main->tracker_list()->set_info(info()); + m_main->tracker_controller()->slot_success() = std::bind(&DownloadWrapper::receive_tracker_success, this, std::placeholders::_1); + m_main->tracker_controller()->slot_failure() = std::bind(&DownloadWrapper::receive_tracker_failed, this, std::placeholders::_1); + +diff --git a/src/protocol/handshake_manager.cc b/src/protocol/handshake_manager.cc +index 99592ba8..255aca0b 100644 +--- a/src/protocol/handshake_manager.cc ++++ b/src/protocol/handshake_manager.cc +@@ -95,7 +95,7 @@ HandshakeManager::add_incoming(SocketFd fd, const rak::socket_address& sa) { + + base_type::push_back(h); + } +- ++ + void + HandshakeManager::add_outgoing(const rak::socket_address& sa, DownloadMain* download) { + if (!manager->connection_manager()->can_connect() || +@@ -175,7 +175,7 @@ HandshakeManager::receive_succeeded(Handshake* handshake) { + handshake->bitfield(), + handshake->encryption()->info(), + handshake->extensions())) != NULL) { +- ++ + manager->client_list()->retrieve_id(&handshake->peer_info()->mutable_client_info(), handshake->peer_info()->id()); + LT_LOG_SA_C(handshake->peer_info()->socket_address(), "Handshake success.", 0); + +@@ -254,7 +254,7 @@ HandshakeManager::setup_socket(SocketFd fd) { + + if (m->send_buffer_size() != 0 && !fd.set_send_buffer_size(m->send_buffer_size())) + return false; +- ++ + if (m->receive_buffer_size() != 0 && !fd.set_receive_buffer_size(m->receive_buffer_size())) + return false; + +diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc +index ea5efc58..976ec696 100644 +--- a/src/torrent/connection_manager.cc ++++ b/src/torrent/connection_manager.cc +@@ -1,45 +1,10 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #include "config.h" + + #include <sys/types.h> + + #include <rak/address_info.h> + #include <rak/socket_address.h> ++#include <net/socket_address.h> + + #include "net/listen.h" + +@@ -70,10 +35,10 @@ resolve_host(const char* host, int family, int socktype, ConnectionManager::slot + rak::socket_address sa; + sa.copy(*ai->address(), ai->length()); + rak::address_info::free_address_info(ai); +- ++ + if (manager->main_thread_main()->is_current()) + thread_base::acquire_global_lock(); +- ++ + slot(sa.c_sockaddr(), 0); + return NULL; + } +@@ -174,6 +139,12 @@ ConnectionManager::set_proxy_address(const sockaddr* sa) { + + uint32_t + ConnectionManager::filter(const sockaddr* sa) { ++ if (!sa_is_any(sa)) { ++ if ((m_block_ipv4 && sa_is_inet(sa)) || ++ (m_block_ipv6 && sa_is_inet6(sa))) ++ return 0; ++ } ++ + if (!m_slot_filter) + return 1; + else +diff --git a/src/torrent/connection_manager.h b/src/torrent/connection_manager.h +index 09ccdd28..2c44357f 100644 +--- a/src/torrent/connection_manager.h ++++ b/src/torrent/connection_manager.h +@@ -1,41 +1,3 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- +-// Add some helpfull words here. +- + #ifndef LIBTORRENT_CONNECTION_MANAGER_H + #define LIBTORRENT_CONNECTION_MANAGER_H + +@@ -106,7 +68,7 @@ public: + + ConnectionManager(); + ~ConnectionManager(); +- ++ + // Check that we have not surpassed the max number of open sockets + // and that we're allowed to connect to the socket address. + // +@@ -129,7 +91,7 @@ public: + void set_priority(priority_type p) { m_priority = p; } + void set_send_buffer_size(uint32_t s); + void set_receive_buffer_size(uint32_t s); +- void set_encryption_options(uint32_t options); ++ void set_encryption_options(uint32_t options); + + // Setting the addresses creates a copy of the address. + const sockaddr* bind_address() const { return m_bindAddress; } +@@ -144,7 +106,7 @@ public: + void set_filter(const slot_filter_type& s) { m_slot_filter = s; } + + bool listen_open(port_type begin, port_type end); +- void listen_close(); ++ void listen_close(); + + // Since trackers need our port number, it doesn't get cleared after + // 'listen_close()'. The client may change the reported port number, +@@ -208,4 +170,3 @@ private: + } + + #endif +- +diff --git a/src/torrent/download_info.h b/src/torrent/download_info.h +index 2c4dbaf2..22f936c3 100644 +--- a/src/torrent/download_info.h ++++ b/src/torrent/download_info.h +@@ -1,39 +1,3 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #ifndef LIBTORRENT_DOWNLOAD_INFO_H + #define LIBTORRENT_DOWNLOAD_INFO_H + +diff --git a/src/torrent/http.h b/src/torrent/http.h +index c605afa5..c5d43016 100644 +--- a/src/torrent/http.h ++++ b/src/torrent/http.h +@@ -1,47 +1,11 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #ifndef LIBTORRENT_HTTP_H + #define LIBTORRENT_HTTP_H + +-#include <string> +-#include <functional> +-#include <iosfwd> +-#include <list> +-#include <torrent/common.h> ++#import <string> ++#import <functional> ++#import <iosfwd> ++#import <list> ++#import <torrent/common.h> + + namespace torrent { + +@@ -60,59 +24,75 @@ class LIBTORRENT_EXPORT Http { + + static const int flag_delete_self = 0x1; + static const int flag_delete_stream = 0x2; ++ static const int flag_only_ipv4 = 0x8; ++ static const int flag_only_ipv6 = 0x10; + + Http() : m_flags(0), m_stream(NULL), m_timeout(0) {} + virtual ~Http(); + + // Start must never throw on bad input. Calling start/stop on an + // object in the wrong state should throw a torrent::internal_error. +- virtual void start() = 0; +- virtual void close() = 0; ++ virtual void start() = 0; ++ virtual void close() = 0; + +- int flags() const { return m_flags; } ++ auto flags() const -> int; + +- void set_delete_self() { m_flags |= flag_delete_self; } +- void set_delete_stream() { m_flags |= flag_delete_stream; } ++ void set_delete_self(); ++ void set_delete_stream(); + +- const std::string& url() const { return m_url; } +- void set_url(const std::string& url) { m_url = url; } ++ auto url() const -> const std::string&; ++ void set_url(const std::string& url); + + // Make sure the output stream does not have any bad/failed bits set. +- std::iostream* stream() { return m_stream; } +- void set_stream(std::iostream* str) { m_stream = str; } +- +- uint32_t timeout() const { return m_timeout; } +- void set_timeout(uint32_t seconds) { m_timeout = seconds; } ++ auto stream() -> std::iostream*; ++ void set_stream(std::iostream* str); ++ ++ auto timeout() const -> uint32_t; ++ void set_timeout(uint32_t seconds); + + // The owner of the Http object must close it as soon as possible + // after receiving the signal, as the implementation may allocate + // limited resources during its lifetime. +- signal_void& signal_done() { return m_signal_done; } +- signal_string& signal_failed() { return m_signal_failed; } ++ auto signal_done() -> signal_void&; ++ auto signal_failed() -> signal_string&; + + // Guaranteed to return a valid object or throw a internal_error. The + // caller takes ownership of the returned object. +- static slot_http& slot_factory() { return m_factory; } ++ static slot_http& slot_factory(); + + protected: +- void trigger_done(); +- void trigger_failed(const std::string& message); ++ void trigger_done(); ++ void trigger_failed(const std::string& message); + +- int m_flags; +- std::string m_url; +- std::iostream* m_stream; +- uint32_t m_timeout; ++ int m_flags; ++ std::string m_url; ++ std::iostream* m_stream; ++ uint32_t m_timeout; + +- signal_void m_signal_done; +- signal_string m_signal_failed; ++ signal_void m_signal_done; ++ signal_string m_signal_failed; + + private: + Http(const Http&); +- void operator = (const Http&); ++ void operator = (const Http&); + +- static slot_http m_factory; ++ static slot_http m_factory; + }; + ++inline auto Http::slot_factory() -> Http::slot_http& { return m_factory; } ++ ++inline auto Http::flags() const -> int { return m_flags; } ++inline void Http::set_delete_self() { m_flags |= flag_delete_self; } ++inline void Http::set_delete_stream() { m_flags |= flag_delete_stream; } ++inline auto Http::url() const -> const std::string& { return m_url; } ++inline void Http::set_url(const std::string& url) { m_url = url; } ++inline auto Http::stream() -> std::iostream* { return m_stream; } ++inline void Http::set_stream(std::iostream* str) { m_stream = str; } ++inline auto Http::timeout() const -> uint32_t { return m_timeout; } ++inline void Http::set_timeout(uint32_t seconds) { m_timeout = seconds; } ++inline auto Http::signal_done() -> signal_void& { return m_signal_done; } ++inline auto Http::signal_failed() -> signal_string& { return m_signal_failed; } ++ + } + + #endif +diff --git a/src/torrent/tracker.cc b/src/torrent/tracker.cc +index 68597a1a..6fc95445 100644 +--- a/src/torrent/tracker.cc ++++ b/src/torrent/tracker.cc +@@ -1,53 +1,18 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- +-#include "config.h" +- +-#include <algorithm> +- +-#include "exceptions.h" +-#include "globals.h" +-#include "tracker.h" +-#include "tracker_list.h" ++#import "config.h" ++ ++#import <algorithm> ++ ++#import "exceptions.h" ++#import "globals.h" ++#import "tracker.h" ++#import "tracker_list.h" + + namespace torrent { + +-Tracker::Tracker(TrackerList* parent, const std::string& url, int flags) : ++Tracker::Tracker(DownloadInfo* info, const std::string& url, int flags) : + m_flags(flags), +- m_parent(parent), ++ m_info(info), ++ + m_group(0), + m_url(url), + +@@ -82,9 +47,7 @@ Tracker::enable() { + return; + + m_flags |= flag_enabled; +- +- if (m_parent->slot_tracker_enabled()) +- m_parent->slot_tracker_enabled()(this); ++ m_slot_tracker_enabled(); + } + + void +@@ -94,9 +57,7 @@ Tracker::disable() { + + close(); + m_flags &= ~flag_enabled; +- +- if (m_parent->slot_tracker_disabled()) +- m_parent->slot_tracker_disabled()(this); ++ m_slot_tracker_disabled(); + } + + uint32_t +diff --git a/src/torrent/tracker.h b/src/torrent/tracker.h +index bd7546a9..39ecec28 100644 +--- a/src/torrent/tracker.h ++++ b/src/torrent/tracker.h +@@ -1,13 +1,15 @@ + #ifndef LIBTORRENT_TRACKER_H + #define LIBTORRENT_TRACKER_H + +-#include <string> +-#include <cinttypes> +-#include <torrent/common.h> ++#import <functional> ++#import <string> ++#import <cinttypes> ++#import <torrent/common.h> + + namespace torrent { + + class AddressList; ++class DownloadInfo; + class TrackerList; + + class LIBTORRENT_EXPORT Tracker { +@@ -55,8 +57,6 @@ public: + void enable(); + void disable(); + +- TrackerList* parent() { return m_parent; } +- + uint32_t group() const { return m_group; } + virtual Type type() const = 0; + +@@ -96,7 +96,7 @@ public: + static std::string scrape_url_from(std::string url); + + protected: +- Tracker(TrackerList* parent, const std::string& url, int flags = 0); ++ Tracker(DownloadInfo* info, const std::string& url, int flags = 0); + Tracker(const Tracker& t); + void operator = (const Tracker& t); + +@@ -116,8 +116,8 @@ protected: + void set_min_interval(int v) { m_min_interval = std::min(std::max(300, v), 4 * 3600); } + + int m_flags; ++ DownloadInfo* m_info; + +- TrackerList* m_parent; + uint32_t m_group; + + std::string m_url; +@@ -147,6 +147,26 @@ protected: + // there's been in the recent past. + uint32_t m_request_time_last; + uint32_t m_request_counter; ++ ++public: ++ auto& slot_success() { return m_slot_success; } ++ auto& slot_failure() { return m_slot_failure; } ++ auto& slot_scrape_success() { return m_slot_scrape_success; } ++ auto& slot_scrape_failure() { return m_slot_scrape_failure; } ++ auto& slot_tracker_enabled() { return m_slot_tracker_enabled; } ++ auto& slot_tracker_disabled() { return m_slot_tracker_disabled; } ++ auto& slot_key() { return m_slot_key; } ++ auto& slot_numwant() { return m_slot_numwant; } ++ ++protected: ++ std::function<void (AddressList* l)> m_slot_success; ++ std::function<void (const std::string& msg)> m_slot_failure; ++ std::function<void ()> m_slot_scrape_success; ++ std::function<void (const std::string& msg)> m_slot_scrape_failure; ++ std::function<void ()> m_slot_tracker_enabled; ++ std::function<void ()> m_slot_tracker_disabled; ++ std::function<uint32_t ()> m_slot_key; ++ std::function<int32_t ()> m_slot_numwant; + }; + + inline bool +diff --git a/src/torrent/tracker_controller.cc b/src/torrent/tracker_controller.cc +index ddbf6538..abf77793 100644 +--- a/src/torrent/tracker_controller.cc ++++ b/src/torrent/tracker_controller.cc +@@ -1,51 +1,15 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- +-#include "config.h" ++#import "config.h" + +-#include "exceptions.h" +-#include "download_info.h" +-#include "tracker.h" +-#include "tracker_controller.h" +-#include "tracker_list.h" ++#import "exceptions.h" ++#import "download_info.h" ++#import "tracker.h" ++#import "tracker_controller.h" ++#import "tracker_list.h" + +-#include "rak/priority_queue_default.h" +-#include "utils/log.h" ++#import "rak/priority_queue_default.h" ++#import "utils/log.h" + +-#include "globals.h" ++#import "globals.h" + + #define LT_LOG_TRACKER(log_level, log_fmt, ...) \ + lt_log_print_info(LOG_TRACKER_##log_level, m_tracker_list->info(), "tracker_controller", log_fmt, __VA_ARGS__); +@@ -220,7 +184,7 @@ TrackerController::send_stop_event() { + if (!(*itr)->is_in_use()) + continue; + +- m_tracker_list->send_state(*itr, Tracker::EVENT_STOPPED); ++ m_tracker_list->send_state(itr->get(), Tracker::EVENT_STOPPED); + } + + // Timer... +@@ -251,7 +215,7 @@ TrackerController::send_completed_event() { + if (!(*itr)->is_in_use()) + continue; + +- m_tracker_list->send_state(*itr, Tracker::EVENT_COMPLETED); ++ m_tracker_list->send_state(itr->get(), Tracker::EVENT_COMPLETED); + } + + // Timer... +@@ -412,7 +376,7 @@ tracker_find_preferred(TrackerList::iterator first, TrackerList::iterator last, + uint32_t preferred_time_last = ~uint32_t(); + + for (; first != last; first++) { +- uint32_t tracker_timeout = tracker_next_timeout_promiscuous(*first); ++ uint32_t tracker_timeout = tracker_next_timeout_promiscuous(first->get()); + + if (tracker_timeout != 0) { + *next_timeout = std::min(tracker_timeout, *next_timeout); +@@ -459,7 +423,7 @@ TrackerController::do_timeout() { + preferred = tracker_find_preferred(preferred, group_end, &next_timeout); + + } else { +- uint32_t tracker_timeout = tracker_next_timeout_promiscuous(*preferred); ++ uint32_t tracker_timeout = tracker_next_timeout_promiscuous(preferred->get()); + + if (tracker_timeout != 0) { + next_timeout = std::min(tracker_timeout, next_timeout); +@@ -511,7 +475,7 @@ TrackerController::do_scrape() { + + while (itr != group_end) { + if ((*itr)->can_scrape() && (*itr)->is_usable()) { +- m_tracker_list->send_scrape(*itr); ++ m_tracker_list->send_scrape(itr->get()); + break; + } + +diff --git a/src/torrent/tracker_controller.h b/src/torrent/tracker_controller.h +index 9452be0f..4af2f4b9 100644 +--- a/src/torrent/tracker_controller.h ++++ b/src/torrent/tracker_controller.h +@@ -1,47 +1,11 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #ifndef LIBTORRENT_TRACKER_CONTROLLER_H + #define LIBTORRENT_TRACKER_CONTROLLER_H + +-#include <functional> +-#include <string> ++#import <functional> ++#import <string> + +-#include <torrent/common.h> +-#include <torrent/tracker.h> ++#import <torrent/common.h> ++#import <torrent/tracker.h> + + // Refactor: + namespace rak { class priority_item; } +@@ -56,11 +20,6 @@ class LIBTORRENT_EXPORT TrackerController { + public: + typedef AddressList address_list; + +- typedef std::function<void (void)> slot_void; +- typedef std::function<void (const std::string&)> slot_string; +- typedef std::function<uint32_t (AddressList*)> slot_address_list; +- typedef std::function<void (Tracker*)> slot_tracker; +- + static const int flag_send_update = 0x1; + static const int flag_send_completed = 0x2; + static const int flag_send_start = 0x4; +@@ -120,18 +79,14 @@ public: + void receive_tracker_enabled(Tracker* tb); + void receive_tracker_disabled(Tracker* tb); + +- slot_void& slot_timeout() { return m_slot_timeout; } +- slot_address_list& slot_success() { return m_slot_success; } +- slot_string& slot_failure() { return m_slot_failure; } +- +- slot_tracker& slot_tracker_enabled() { return m_slot_tracker_enabled; } +- slot_tracker& slot_tracker_disabled() { return m_slot_tracker_disabled; } +- + // TEMP: + rak::priority_item* task_timeout(); + rak::priority_item* task_scrape(); + + private: ++ TrackerController() = delete; ++ void operator = (const TrackerController&) = delete; ++ + void do_timeout(); + void do_scrape(); + +@@ -139,21 +94,25 @@ private: + + inline int current_send_state() const; + +- TrackerController(); +- void operator = (const TrackerController&); +- + int m_flags; + TrackerList* m_tracker_list; + +- slot_void m_slot_timeout; +- slot_address_list m_slot_success; +- slot_string m_slot_failure; +- +- slot_tracker m_slot_tracker_enabled; +- slot_tracker m_slot_tracker_disabled; +- + // Refactor this out. + tracker_controller_private* m_private; ++ ++public: ++ auto& slot_timeout() { return m_slot_timeout; } ++ auto& slot_success() { return m_slot_success; } ++ auto& slot_failure() { return m_slot_failure; } ++ auto& slot_tracker_enabled() { return m_slot_tracker_enabled; } ++ auto& slot_tracker_disabled() { return m_slot_tracker_disabled; } ++ ++private: ++ std::function<void (void)> m_slot_timeout; ++ std::function<uint32_t (AddressList*)> m_slot_success; ++ std::function<void (const std::string&)> m_slot_failure; ++ std::function<void (Tracker*)> m_slot_tracker_enabled; ++ std::function<void (Tracker*)> m_slot_tracker_disabled; + }; + + uint32_t tracker_next_timeout(Tracker* tracker, int controller_flags); +diff --git a/src/torrent/tracker_list.cc b/src/torrent/tracker_list.cc +index 625055da..4daf45ce 100644 +--- a/src/torrent/tracker_list.cc ++++ b/src/torrent/tracker_list.cc +@@ -1,64 +1,31 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- +-#include "config.h" +- +-#include <functional> +-#include <rak/functional.h> +- +-#include "net/address_list.h" +-#include "torrent/utils/log.h" +-#include "torrent/utils/option_strings.h" +-#include "torrent/download_info.h" +-#include "tracker/tracker_dht.h" +-#include "tracker/tracker_http.h" +-#include "tracker/tracker_udp.h" +- +-#include "globals.h" +-#include "exceptions.h" +-#include "tracker.h" +-#include "tracker_list.h" ++#import "config.h" ++ ++#import <functional> ++#import <rak/functional.h> ++ ++#import "net/address_list.h" ++#import "torrent/utils/log.h" ++#import "torrent/utils/option_strings.h" ++#import "torrent/download_info.h" ++#import "tracker/tracker_dht.h" ++#import "tracker/tracker_http.h" ++#import "tracker/tracker_udp.h" ++ ++#import "globals.h" ++#import "exceptions.h" ++#import "tracker.h" ++#import "tracker_list.h" + + #define LT_LOG_TRACKER(log_level, log_fmt, ...) \ + lt_log_print_info(LOG_TRACKER_##log_level, info(), "tracker_list", log_fmt, __VA_ARGS__); + ++#define LT_LOG_STATE_DEBUG(log_fmt, ...) \ ++ lt_log_print_info(LOG_TRACKER_STATE_DEBUG, info(), "tracker_list::state_debug", log_fmt, __VA_ARGS__); ++ + namespace torrent { + +-TrackerList::TrackerList() : +- m_info(NULL), ++TrackerList::TrackerList(DownloadInfo* info) : ++ m_info(info), + m_state(DownloadInfo::STOPPED), + + m_key(0), +@@ -67,22 +34,22 @@ TrackerList::TrackerList() : + + bool + TrackerList::has_active() const { +- return std::find_if(begin(), end(), std::mem_fun(&Tracker::is_busy)) != end(); ++ return std::find_if(begin(), end(), [](auto& v){ return v->is_busy(); }) != end(); + } + + bool + TrackerList::has_active_not_scrape() const { +- return std::find_if(begin(), end(), std::mem_fun(&Tracker::is_busy_not_scrape)) != end(); ++ return std::find_if(begin(), end(), [](auto& v){ return v->is_busy_not_scrape(); }) != end(); + } + + bool + TrackerList::has_active_in_group(uint32_t group) const { +- return std::find_if(begin_group(group), end_group(group), std::mem_fun(&Tracker::is_busy)) != end_group(group); ++ return std::find_if(begin_group(group), end_group(group), [](auto& v){ return v->is_busy(); }) != end_group(group); + } + + bool + TrackerList::has_active_not_scrape_in_group(uint32_t group) const { +- return std::find_if(begin_group(group), end_group(group), std::mem_fun(&Tracker::is_busy_not_scrape)) != end_group(group); ++ return std::find_if(begin_group(group), end_group(group), [](auto& v){ return v->is_busy_not_scrape(); }) != end_group(group); + } + + // Need a custom predicate because the is_usable function is virtual. +@@ -97,7 +64,7 @@ TrackerList::has_usable() const { + + unsigned int + TrackerList::count_active() const { +- return std::count_if(begin(), end(), std::mem_fun(&Tracker::is_busy)); ++ return std::count_if(begin(), end(), [](auto& v){ return v->is_busy(); }); + } + + unsigned int +@@ -123,29 +90,29 @@ TrackerList::disown_all_including(int event_bitmap) { + } + } + +-void +-TrackerList::clear() { +- std::for_each(begin(), end(), rak::call_delete<Tracker>()); +- base_type::clear(); +-} +- + void + TrackerList::clear_stats() { +- std::for_each(begin(), end(), std::mem_fun(&Tracker::clear_stats)); ++ std::for_each(begin(), end(), [](auto& v){ return v->clear_stats(); }); + } + + void + TrackerList::send_state(Tracker* tracker, int new_event) { +- if (!tracker->is_usable() || new_event == Tracker::EVENT_SCRAPE) ++ if (!tracker->is_usable() || new_event == Tracker::EVENT_SCRAPE) { ++ LT_LOG_STATE_DEBUG("send state skipped: !is_usable || new_event == EVENT_SCRAPE", 0) + return; ++ } + + if (tracker->is_busy()) { +- if (tracker->latest_event() != Tracker::EVENT_SCRAPE) ++ if (tracker->latest_event() != Tracker::EVENT_SCRAPE) { ++ LT_LOG_STATE_DEBUG("send state skipped: already making a non-scrape request", 0) + return; ++ } + + tracker->close(); + } + ++ LT_LOG_STATE_DEBUG("sending state", 0) ++ + tracker->send_state(new_event); + tracker->inc_request_counter(); + +@@ -156,14 +123,22 @@ TrackerList::send_state(Tracker* tracker, int new_event) { + + void + TrackerList::send_scrape(Tracker* tracker) { +- if (tracker->is_busy() || !tracker->is_usable()) ++ if (tracker->is_busy() || !tracker->is_usable()) { ++ LT_LOG_STATE_DEBUG("send scrape skipped: is_busy || !is_usable", 0) + return; ++ } + +- if (!(tracker->flags() & Tracker::flag_can_scrape)) ++ if (!(tracker->flags() & Tracker::flag_can_scrape)) { ++ LT_LOG_STATE_DEBUG("send scrape skipped: !can_scrape", 0) + return; ++ } + +- if (rak::timer::from_seconds(tracker->scrape_time_last()) + rak::timer::from_seconds(10 * 60) > cachedTime ) ++ if (rak::timer::from_seconds(tracker->scrape_time_last()) + rak::timer::from_seconds(10 * 60) > cachedTime ) { ++ LT_LOG_STATE_DEBUG("send scrape skipped: time_last:%" PRIu32 " cached_time:%" PRIu32, tracker->scrape_time_last(), cachedTime.seconds()) + return; ++ } ++ ++ LT_LOG_STATE_DEBUG("sending scrape", 0) + + tracker->send_scrape(); + tracker->inc_request_counter(); +@@ -172,11 +147,20 @@ TrackerList::send_scrape(Tracker* tracker) { + tracker->group(), tracker->url().c_str()); + } + ++// TODO: Make tracker shared_ptr. + TrackerList::iterator + TrackerList::insert(unsigned int group, Tracker* tracker) { + tracker->set_group(group); +- +- iterator itr = base_type::insert(end_group(group), tracker); ++ tracker->slot_success() = std::bind(&TrackerList::receive_success, this, tracker, std::placeholders::_1); ++ tracker->slot_failure() = std::bind(&TrackerList::receive_failed, this, tracker, std::placeholders::_1); ++ tracker->slot_scrape_success() = std::bind(&TrackerList::receive_scrape_success, this, tracker); ++ tracker->slot_scrape_failure() = std::bind(&TrackerList::receive_scrape_failed, this, tracker, std::placeholders::_1); ++ tracker->slot_tracker_enabled() = std::bind(&TrackerList::receive_tracker_enabled, this, tracker); ++ tracker->slot_tracker_disabled() = std::bind(&TrackerList::receive_tracker_disabled, this, tracker); ++ tracker->slot_key() = std::bind(&TrackerList::key, this); ++ tracker->slot_numwant() = std::bind(&TrackerList::numwant, this); ++ ++ iterator itr = base_type::insert(end_group(group), std::shared_ptr<Tracker>(tracker)); + + if (m_slot_tracker_enabled) + m_slot_tracker_enabled(tracker); +@@ -195,13 +179,13 @@ TrackerList::insert_url(unsigned int group, const std::string& url, bool extra_t + + if (std::strncmp("http://", url.c_str(), 7) == 0 || + std::strncmp("https://", url.c_str(), 8) == 0) { +- tracker = new TrackerHttp(this, url, flags); ++ tracker = new TrackerHttp(m_info, url, flags); + + } else if (std::strncmp("udp://", url.c_str(), 6) == 0) { +- tracker = new TrackerUdp(this, url, flags); ++ tracker = new TrackerUdp(m_info, url, flags); + + } else if (std::strncmp("dht://", url.c_str(), 6) == 0 && TrackerDht::is_allowed()) { +- tracker = new TrackerDht(this, url, flags); ++ tracker = new TrackerDht(m_info, url, flags); + + } else { + LT_LOG_TRACKER(WARN, "could find matching tracker protocol (url:%s)", url.c_str()); +@@ -213,6 +197,7 @@ TrackerList::insert_url(unsigned int group, const std::string& url, bool extra_t + } + + LT_LOG_TRACKER(INFO, "added tracker (group:%i url:%s)", group, url.c_str()); ++ + insert(group, tracker); + } + +@@ -240,7 +225,7 @@ TrackerList::find_usable(const_iterator itr) const { + + TrackerList::iterator + TrackerList::find_next_to_request(iterator itr) { +- TrackerList::iterator preferred = itr = std::find_if(itr, end(), std::mem_fun(&Tracker::can_request_state)); ++ TrackerList::iterator preferred = itr = std::find_if(itr, end(), [](auto& v){ return v->can_request_state(); }); + + if (preferred == end() || (*preferred)->failed_counter() == 0) + return preferred; +@@ -266,12 +251,12 @@ TrackerList::find_next_to_request(iterator itr) { + + TrackerList::iterator + TrackerList::begin_group(unsigned int group) { +- return std::find_if(begin(), end(), rak::less_equal(group, std::mem_fun(&Tracker::group))); ++ return std::find_if(begin(), end(), rak::less_equal(group, [](auto& v){ return v->group(); })); + } + + TrackerList::const_iterator + TrackerList::begin_group(unsigned int group) const { +- return std::find_if(begin(), end(), rak::less_equal(group, std::mem_fun(&Tracker::group))); ++ return std::find_if(begin(), end(), rak::less_equal(group, [](auto& v){ return v->group(); })); + } + + TrackerList::size_type +@@ -384,4 +369,16 @@ TrackerList::receive_scrape_failed(Tracker* tb, const std::string& msg) { + m_slot_scrape_failed(tb, msg); + } + ++void ++TrackerList::receive_tracker_enabled(Tracker* t) { ++ if (m_slot_tracker_enabled) ++ m_slot_tracker_enabled(t); ++} ++ ++void ++TrackerList::receive_tracker_disabled(Tracker* t) { ++ if (m_slot_tracker_disabled) ++ m_slot_tracker_disabled(t); ++} ++ + } +diff --git a/src/torrent/tracker_list.h b/src/torrent/tracker_list.h +index bb06f8af..9c1c9f6f 100644 +--- a/src/torrent/tracker_list.h ++++ b/src/torrent/tracker_list.h +@@ -1,47 +1,12 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #ifndef LIBTORRENT_TRACKER_LIST_H + #define LIBTORRENT_TRACKER_LIST_H + +-#include <algorithm> +-#include <functional> +-#include <string> +-#include <vector> +-#include <torrent/common.h> ++#import <algorithm> ++#import <functional> ++#import <memory> ++#import <string> ++#import <vector> ++#import <torrent/common.h> + + namespace torrent { + +@@ -57,16 +22,12 @@ class Tracker; + // tracker to the beginning of the subgroup and start from the + // beginning of the whole list. + +-class LIBTORRENT_EXPORT TrackerList : private std::vector<Tracker*> { ++class LIBTORRENT_EXPORT TrackerList : private std::vector<std::shared_ptr<Tracker>> { + public: + friend class DownloadWrapper; + +- typedef std::vector<Tracker*> base_type; +- typedef AddressList address_list; +- +- typedef std::function<void (Tracker*)> slot_tracker; +- typedef std::function<void (Tracker*, const std::string&)> slot_string; +- typedef std::function<uint32_t (Tracker*, AddressList*)> slot_address_list; ++ typedef std::vector<std::shared_ptr<Tracker>> base_type; ++ typedef AddressList address_list; + + using base_type::value_type; + +@@ -85,9 +46,10 @@ public: + using base_type::back; + + using base_type::at; ++ using base_type::clear; + using base_type::operator[]; + +- TrackerList(); ++ TrackerList(DownloadInfo* info); + + bool has_active() const; + bool has_active_not_scrape() const; +@@ -103,7 +65,6 @@ public: + + void disown_all_including(int event_bitmap); + +- void clear(); + void clear_stats(); + + iterator insert(unsigned int group, Tracker* tracker); +@@ -124,7 +85,9 @@ public: + int32_t numwant() const { return m_numwant; } + void set_numwant(int32_t n) { m_numwant = n; } + +- iterator find(Tracker* tb) { return std::find(begin(), end(), tb); } ++ auto find(Tracker* tb) -> iterator; ++ ++ // iterator find(Tracker* tb) { return std::find(begin(), end(), tb); } + iterator find_url(const std::string& url); + + iterator find_usable(iterator itr); +@@ -145,28 +108,17 @@ public: + + void receive_success(Tracker* tb, AddressList* l); + void receive_failed(Tracker* tb, const std::string& msg); +- + void receive_scrape_success(Tracker* tb); + void receive_scrape_failed(Tracker* tb, const std::string& msg); +- +- // Used by libtorrent internally. +- slot_address_list& slot_success() { return m_slot_success; } +- slot_string& slot_failure() { return m_slot_failed; } +- +- slot_tracker& slot_scrape_success() { return m_slot_scrape_success; } +- slot_string& slot_scrape_failure() { return m_slot_scrape_failed; } +- +- slot_tracker& slot_tracker_enabled() { return m_slot_tracker_enabled; } +- slot_tracker& slot_tracker_disabled() { return m_slot_tracker_disabled; } ++ void receive_tracker_enabled(Tracker* t); ++ void receive_tracker_disabled(Tracker* t); + + protected: +- void set_info(DownloadInfo* info) { m_info = info; } +- + void set_state(int s) { m_state = s; } + + private: +- TrackerList(const TrackerList&) LIBTORRENT_NO_EXPORT; +- void operator = (const TrackerList&) LIBTORRENT_NO_EXPORT; ++ TrackerList(const TrackerList&) = delete; ++ void operator = (const TrackerList&) = delete; + + DownloadInfo* m_info; + int m_state; +@@ -174,19 +126,26 @@ private: + uint32_t m_key; + int32_t m_numwant; + +- slot_address_list m_slot_success; +- slot_string m_slot_failed; +- +- slot_tracker m_slot_scrape_success; +- slot_string m_slot_scrape_failed; ++public: ++ auto& slot_success() { return m_slot_success; } ++ auto& slot_failure() { return m_slot_failed; } ++ auto& slot_scrape_success() { return m_slot_scrape_success; } ++ auto& slot_scrape_failure() { return m_slot_scrape_failed; } ++ auto& slot_tracker_enabled() { return m_slot_tracker_enabled; } ++ auto& slot_tracker_disabled() { return m_slot_tracker_disabled; } + +- slot_tracker m_slot_tracker_enabled; +- slot_tracker m_slot_tracker_disabled; ++private: ++ std::function<uint32_t (Tracker*, AddressList*)> m_slot_success; ++ std::function<void (Tracker*, const std::string&)> m_slot_failed; ++ std::function<void (Tracker*)> m_slot_scrape_success; ++ std::function<void (Tracker*, const std::string&)> m_slot_scrape_failed; ++ std::function<void (Tracker*)> m_slot_tracker_enabled; ++ std::function<void (Tracker*)> m_slot_tracker_disabled; + }; + + inline void + TrackerList::send_state_idx(unsigned idx, int new_event) { +- send_state(at(idx), new_event); ++ send_state(at(idx).get(), new_event); + } + + inline void +@@ -194,7 +153,12 @@ TrackerList::send_state_itr(iterator itr, int new_event) { + if (itr == end()) + return; + +- send_state(*itr, new_event); ++ send_state(itr->get(), new_event); ++} ++ ++inline TrackerList::iterator ++TrackerList::find(Tracker* tb) { ++ return std::find_if(begin(), end(), [tb](auto& v){ return v.get() == tb; }); + } + + } +diff --git a/src/torrent/utils/log.h b/src/torrent/utils/log.h +index fe6127d6..863199bc 100644 +--- a/src/torrent/utils/log.h ++++ b/src/torrent/utils/log.h +@@ -108,6 +108,8 @@ enum { + + LOG_SYSTEM, + ++ LOG_TRACKER_STATE_DEBUG, ++ + LOG_UI_EVENTS, + + LOG_GROUP_MAX_SIZE +diff --git a/src/torrent/utils/option_strings.cc b/src/torrent/utils/option_strings.cc +index 101e2688..eb3798d8 100644 +--- a/src/torrent/utils/option_strings.cc ++++ b/src/torrent/utils/option_strings.cc +@@ -232,6 +232,8 @@ const char* option_list_log_group[] = { + + "system", + ++ "tracker_state_debug", ++ + "ui_events", + + NULL +diff --git a/src/tracker/tracker_dht.cc b/src/tracker/tracker_dht.cc +index d48a7f5f..8e09036d 100644 +--- a/src/tracker/tracker_dht.cc ++++ b/src/tracker/tracker_dht.cc +@@ -58,8 +58,8 @@ const char* TrackerDht::states[] = { "Idle", "Searching", "Announcing" }; + + bool TrackerDht::is_allowed() { return manager->dht_manager()->is_valid(); } + +-TrackerDht::TrackerDht(TrackerList* parent, const std::string& url, int flags) : +- Tracker(parent, url, flags), ++TrackerDht::TrackerDht(DownloadInfo* info, const std::string& url, int flags) : ++ Tracker(info, url, flags), + m_state(state_idle) { + + if (!manager->dht_manager()->is_valid()) +@@ -83,11 +83,8 @@ TrackerDht::is_usable() const { + + void + TrackerDht::send_state(int state) { +- if (m_parent == NULL) +- throw internal_error("TrackerDht::send_state(...) does not have a valid m_parent."); +- + if (is_busy()) { +- manager->dht_manager()->router()->cancel_announce(m_parent->info(), this); ++ manager->dht_manager()->router()->cancel_announce(m_info, this); + + if (is_busy()) + throw internal_error("TrackerDht::send_state cancel_announce did not cancel announce."); +@@ -103,7 +100,7 @@ TrackerDht::send_state(int state) { + if (!manager->dht_manager()->is_active()) + return receive_failed("DHT server not active."); + +- manager->dht_manager()->router()->announce(m_parent->info(), this); ++ manager->dht_manager()->router()->announce(m_info, this); + + set_normal_interval(20 * 60); + set_min_interval(0); +@@ -112,7 +109,7 @@ TrackerDht::send_state(int state) { + void + TrackerDht::close() { + if (is_busy()) +- manager->dht_manager()->router()->cancel_announce(m_parent->info(), this); ++ manager->dht_manager()->router()->cancel_announce(m_info, this); + } + + void +@@ -139,7 +136,7 @@ TrackerDht::receive_success() { + throw internal_error("TrackerDht::receive_success called while not busy."); + + m_state = state_idle; +- m_parent->receive_success(this, &m_peers); ++ m_slot_success(&m_peers); + m_peers.clear(); + } + +@@ -149,7 +146,7 @@ TrackerDht::receive_failed(const char* msg) { + throw internal_error("TrackerDht::receive_failed called while not busy."); + + m_state = state_idle; +- m_parent->receive_failed(this, msg); ++ m_slot_failure(msg); + m_peers.clear(); + } + +diff --git a/src/tracker/tracker_dht.h b/src/tracker/tracker_dht.h +index d2a73ca7..bdc2adae 100644 +--- a/src/tracker/tracker_dht.h ++++ b/src/tracker/tracker_dht.h +@@ -45,7 +45,7 @@ namespace torrent { + + class TrackerDht : public Tracker { + public: +- TrackerDht(TrackerList* parent, const std::string& url, int flags); ++ TrackerDht(DownloadInfo* info, const std::string& url, int flags); + ~TrackerDht(); + + typedef enum { +diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc +index 22c409a1..6daf0308 100644 +--- a/src/tracker/tracker_http.cc ++++ b/src/tracker/tracker_http.cc +@@ -25,15 +25,15 @@ + #import "manager.h" + + #define LT_LOG_TRACKER(log_level, log_fmt, ...) \ +- lt_log_print_info(LOG_TRACKER_##log_level, m_parent->info(), "tracker", "[%u] " log_fmt, group(), __VA_ARGS__); ++ lt_log_print_info(LOG_TRACKER_##log_level, m_info, "tracker", "[%u] " log_fmt, group(), __VA_ARGS__); + + #define LT_LOG_TRACKER_DUMP(log_level, log_dump_data, log_dump_size, log_fmt, ...) \ +- lt_log_print_info_dump(LOG_TRACKER_##log_level, log_dump_data, log_dump_size, m_parent->info(), "tracker", "[%u] " log_fmt, group(), __VA_ARGS__); ++ lt_log_print_info_dump(LOG_TRACKER_##log_level, log_dump_data, log_dump_size, m_info, "tracker", "[%u] " log_fmt, group(), __VA_ARGS__); + + namespace torrent { + +-TrackerHttp::TrackerHttp(TrackerList* parent, const std::string& url, int flags) : +- Tracker(parent, url, flags), ++TrackerHttp::TrackerHttp(DownloadInfo* info, const std::string& url, int flags) : ++ Tracker(info, url, flags), + + m_get(Http::slot_factory()()), + m_data(NULL) { +@@ -70,8 +70,8 @@ void + TrackerHttp::request_prefix(std::stringstream* stream, const std::string& url) { + char hash[61]; + +- *rak::copy_escape_html(m_parent->info()->hash().begin(), +- m_parent->info()->hash().end(), hash) = '\0'; ++ *rak::copy_escape_html(m_info->hash().begin(), ++ m_info->hash().end(), hash) = '\0'; + *stream << url + << (m_dropDeliminator ? '&' : '?') + << "info_hash=" << hash; +@@ -81,9 +81,6 @@ void + TrackerHttp::send_state(int state) { + close_directly(); + +- if (m_parent == NULL) +- throw internal_error("TrackerHttp::send_state(...) does not have a valid m_parent."); +- + m_latest_event = state; + + std::stringstream s; +@@ -91,7 +88,7 @@ TrackerHttp::send_state(int state) { + + char localId[61]; + +- DownloadInfo* info = m_parent->info(); ++ DownloadInfo* info = m_info; + + request_prefix(&s, m_url); + +@@ -99,8 +96,8 @@ TrackerHttp::send_state(int state) { + + s << "&peer_id=" << localId; + +- if (m_parent->key()) +- s << "&key=" << std::hex << std::setw(8) << std::setfill('0') << m_parent->key() << std::dec; ++ if (m_slot_key()) ++ s << "&key=" << std::hex << std::setw(8) << std::setfill('0') << m_slot_key() << std::dec; + + if (!m_tracker_id.empty()) + s << "&trackerid=" << rak::copy_escape_html(m_tracker_id); +@@ -122,8 +119,8 @@ TrackerHttp::send_state(int state) { + if (info->is_compact()) + s << "&compact=1"; + +- if (m_parent->numwant() >= 0 && state != DownloadInfo::STOPPED) +- s << "&numwant=" << m_parent->numwant(); ++ if (m_slot_numwant() >= 0 && state != DownloadInfo::STOPPED) ++ s << "&numwant=" << m_slot_numwant(); + + if (manager->connection_manager()->listen_port()) + s << "&port=" << manager->connection_manager()->listen_port(); +@@ -280,10 +277,12 @@ TrackerHttp::receive_failed(std::string msg) { + + close_directly(); + +- if (m_latest_event == EVENT_SCRAPE) +- m_parent->receive_scrape_failed(this, msg); +- else +- m_parent->receive_failed(this, msg); ++ if (m_latest_event == EVENT_SCRAPE) { ++ m_slot_scrape_failure(msg); ++ return; ++ } ++ ++ m_slot_failure(msg); + } + + void +@@ -330,7 +329,7 @@ TrackerHttp::process_success(const Object& object) { + l.parse_address_compact_ipv6(object.get_key_string("peers6")); + + close_directly(); +- m_parent->receive_success(this, &l); ++ m_slot_success(&l); + } + + void +@@ -341,10 +340,10 @@ TrackerHttp::process_scrape(const Object& object) { + // Add better validation here... + const Object& files = object.get_key("files"); + +- if (!files.has_key_map(m_parent->info()->hash().str())) ++ if (!files.has_key_map(m_info->hash().str())) + return receive_failed("Tracker scrape replay did not contain infohash."); + +- const Object& stats = files.get_key(m_parent->info()->hash().str()); ++ const Object& stats = files.get_key(m_info->hash().str()); + + if (stats.has_key_value("complete")) + m_scrape_complete = std::max<int64_t>(stats.get_key_value("complete"), 0); +@@ -359,7 +358,7 @@ TrackerHttp::process_scrape(const Object& object) { + files.as_map().size(), m_scrape_complete, m_scrape_incomplete, m_scrape_downloaded); + + close_directly(); +- m_parent->receive_scrape_success(this); ++ m_slot_scrape_success(); + } + + } +diff --git a/src/tracker/tracker_http.h b/src/tracker/tracker_http.h +index 2d6adcff..2ceb47db 100644 +--- a/src/tracker/tracker_http.h ++++ b/src/tracker/tracker_http.h +@@ -1,46 +1,10 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #ifndef LIBTORRENT_TRACKER_TRACKER_HTTP_H + #define LIBTORRENT_TRACKER_TRACKER_HTTP_H + +-#include <iosfwd> ++#import <iosfwd> + +-#include "torrent/object.h" +-#include "torrent/tracker.h" ++#import "torrent/object.h" ++#import "torrent/tracker.h" + + namespace torrent { + +@@ -48,7 +12,7 @@ class Http; + + class TrackerHttp : public Tracker { + public: +- TrackerHttp(TrackerList* parent, const std::string& url, int flags); ++ TrackerHttp(DownloadInfo* info, const std::string& url, int flags); + ~TrackerHttp(); + + virtual bool is_busy() const; +diff --git a/src/tracker/tracker_udp.cc b/src/tracker/tracker_udp.cc +index 93493e47..2ce56638 100644 +--- a/src/tracker/tracker_udp.cc ++++ b/src/tracker/tracker_udp.cc +@@ -1,39 +1,3 @@ +-// libTorrent - BitTorrent library +-// Copyright (C) 2005-2011, Jari Sundell +-// +-// This program is free software; you can redistribute it and/or modify +-// it under the terms of the GNU General Public License as published by +-// the Free Software Foundation; either version 2 of the License, or +-// (at your option) any later version. +-// +-// This program is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-// GNU General Public License for more details. +-// +-// You should have received a copy of the GNU General Public License +-// along with this program; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-// In addition, as a special exception, the copyright holders give +-// permission to link the code of portions of this program with the +-// OpenSSL library under certain conditions as described in each +-// individual source file, and distribute linked combinations +-// including the two. +-// +-// You must obey the GNU General Public License in all respects for +-// all of the code used other than OpenSSL. If you modify file(s) +-// with this exception, you may extend this exception to your version +-// of the file(s), but you are not obligated to do so. If you do not +-// wish to do so, delete this exception statement from your version. +-// If you delete this exception statement from all source files in the +-// program, then also delete it here. +-// +-// Contact: Jari Sundell <jaris@ifi.uio.no> +-// +-// Skomakerveien 33 +-// 3185 Skoppum, NORWAY +- + #include "config.h" + + #define __STDC_FORMAT_MACROS +@@ -58,15 +22,15 @@ + #include "manager.h" + + #define LT_LOG_TRACKER(log_level, log_fmt, ...) \ +- lt_log_print_info(LOG_TRACKER_##log_level, m_parent->info(), "tracker_udp", "[%u] " log_fmt, group(), __VA_ARGS__); ++ lt_log_print_info(LOG_TRACKER_##log_level, m_info, "tracker_udp", "[%u] " log_fmt, group(), __VA_ARGS__); + + #define LT_LOG_TRACKER_DUMP(log_level, log_dump_data, log_dump_size, log_fmt, ...) \ +- lt_log_print_info_dump(LOG_TRACKER_##log_level, log_dump_data, log_dump_size, m_parent->info(), "tracker_udp", "[%u] " log_fmt, group(), __VA_ARGS__); ++ lt_log_print_info_dump(LOG_TRACKER_##log_level, log_dump_data, log_dump_size, m_info, "tracker_udp", "[%u] " log_fmt, group(), __VA_ARGS__); + + namespace torrent { + +-TrackerUdp::TrackerUdp(TrackerList* parent, const std::string& url, int flags) : +- Tracker(parent, url, flags), ++TrackerUdp::TrackerUdp(DownloadInfo* info, const std::string& url, int flags) : ++ Tracker(info, url, flags), + + m_port(0), + +@@ -174,8 +138,8 @@ TrackerUdp::start_announce(const sockaddr* sa, int err) { + manager->poll()->insert_write(this); + manager->poll()->insert_error(this); + +- m_tries = m_parent->info()->udp_tries(); +- priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_parent->info()->udp_timeout())).round_seconds()); ++ m_tries = m_info->udp_tries(); ++ priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_info->udp_timeout())).round_seconds()); + } + + void +@@ -230,7 +194,7 @@ TrackerUdp::type() const { + void + TrackerUdp::receive_failed(const std::string& msg) { + close_directly(); +- m_parent->receive_failed(this, msg); ++ m_slot_failure(msg); + } + + void +@@ -241,7 +205,7 @@ TrackerUdp::receive_timeout() { + if (--m_tries == 0) { + receive_failed("unable to connect to UDP tracker"); + } else { +- priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_parent->info()->udp_timeout())).round_seconds()); ++ priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_info->udp_timeout())).round_seconds()); + + manager->poll()->insert_write(this); + } +@@ -275,9 +239,9 @@ TrackerUdp::event_read() { + prepare_announce_input(); + + priority_queue_erase(&taskScheduler, &m_taskTimeout); +- priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_parent->info()->udp_timeout())).round_seconds()); ++ priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_info->udp_timeout())).round_seconds()); + +- m_tries = m_parent->info()->udp_tries(); ++ m_tries = m_info->udp_tries(); + manager->poll()->insert_write(this); + return; + +@@ -325,20 +289,18 @@ TrackerUdp::prepare_connect_input() { + + void + TrackerUdp::prepare_announce_input() { +- DownloadInfo* info = m_parent->info(); +- + m_writeBuffer->reset(); + + m_writeBuffer->write_64(m_connectionId); + m_writeBuffer->write_32(m_action = 1); + m_writeBuffer->write_32(m_transactionId = random()); + +- m_writeBuffer->write_range(info->hash().begin(), info->hash().end()); +- m_writeBuffer->write_range(info->local_id().begin(), info->local_id().end()); ++ m_writeBuffer->write_range(m_info->hash().begin(), m_info->hash().end()); ++ m_writeBuffer->write_range(m_info->local_id().begin(), m_info->local_id().end()); + +- uint64_t uploaded_adjusted = info->uploaded_adjusted(); +- uint64_t completed_adjusted = info->completed_adjusted(); +- uint64_t download_left = info->slot_left()(); ++ uint64_t uploaded_adjusted = m_info->uploaded_adjusted(); ++ uint64_t completed_adjusted = m_info->completed_adjusted(); ++ uint64_t download_left = m_info->slot_left()(); + + m_writeBuffer->write_64(completed_adjusted); + m_writeBuffer->write_64(download_left); +@@ -353,8 +315,8 @@ TrackerUdp::prepare_announce_input() { + local_addr = localAddress->sa_inet()->address_n(); + + m_writeBuffer->write_32_n(local_addr); +- m_writeBuffer->write_32(m_parent->key()); +- m_writeBuffer->write_32(m_parent->numwant()); ++ m_writeBuffer->write_32(m_slot_key()); ++ m_writeBuffer->write_32(m_slot_numwant()); + m_writeBuffer->write_16(manager->connection_manager()->listen_port()); + + if (m_writeBuffer->size_end() != 98) +@@ -398,7 +360,7 @@ TrackerUdp::process_announce_output() { + // Some logic here to decided on whetever we're going to close the + // connection or not? + close_directly(); +- m_parent->receive_success(this, &l); ++ m_slot_success(&l); + + return true; + } +diff --git a/src/tracker/tracker_udp.h b/src/tracker/tracker_udp.h +index aaa7ff67..68a31ef6 100644 +--- a/src/tracker/tracker_udp.h ++++ b/src/tracker/tracker_udp.h +@@ -60,7 +60,7 @@ public: + + static const uint64_t magic_connection_id = 0x0000041727101980ll; + +- TrackerUdp(TrackerList* parent, const std::string& url, int flags); ++ TrackerUdp(DownloadInfo* info, const std::string& url, int flags); + ~TrackerUdp(); + + const char* type_name() const { return "tracker_udp"; } +diff --git a/test/Makefile.am b/test/Makefile.am +index cb00dce3..8d7e6f1d 100644 +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -34,7 +34,9 @@ LibTorrent_Test_Common = \ + helpers/test_fixture.cc \ + helpers/test_fixture.h \ + helpers/test_thread.cc \ +- helpers/test_thread.h ++ helpers/test_thread.h \ ++ mock/http.cc \ ++ mock/http.h + + LibTorrent_Test_Torrent_Net_SOURCES = $(LibTorrent_Test_Common) \ + torrent/net/test_address_info.cc \ +@@ -65,6 +67,16 @@ LibTorrent_Test_Torrent_Utils_SOURCES = $(LibTorrent_Test_Common) \ + LibTorrent_Test_Torrent_SOURCES = $(LibTorrent_Test_Common) \ + torrent/test_http.cc \ + torrent/test_http.h \ ++ torrent/test_tracker_controller.cc \ ++ torrent/test_tracker_controller.h \ ++ torrent/test_tracker_controller_features.cc \ ++ torrent/test_tracker_controller_features.h \ ++ torrent/test_tracker_controller_requesting.cc \ ++ torrent/test_tracker_controller_requesting.h \ ++ torrent/test_tracker_list.cc \ ++ torrent/test_tracker_list.h \ ++ torrent/test_tracker_list_features.cc \ ++ torrent/test_tracker_list_features.h \ + \ + torrent/object_test.cc \ + torrent/object_test.h \ +@@ -74,16 +86,6 @@ LibTorrent_Test_Torrent_SOURCES = $(LibTorrent_Test_Common) \ + torrent/object_static_map_test.h \ + torrent/object_stream_test.cc \ + torrent/object_stream_test.h \ +- torrent/tracker_controller_test.cc \ +- torrent/tracker_controller_test.h \ +- torrent/tracker_controller_features.cc \ +- torrent/tracker_controller_features.h \ +- torrent/tracker_controller_requesting.cc \ +- torrent/tracker_controller_requesting.h \ +- torrent/tracker_list_test.cc \ +- torrent/tracker_list_test.h \ +- torrent/tracker_list_features_test.cc \ +- torrent/tracker_list_features_test.h \ + torrent/tracker_timeout_test.cc \ + torrent/tracker_timeout_test.h + +diff --git a/test/helpers/mock_function.cc b/test/helpers/mock_function.cc +index 83e81551..51fea643 100644 +--- a/test/helpers/mock_function.cc ++++ b/test/helpers/mock_function.cc +@@ -42,14 +42,7 @@ mock_clear(bool ignore_assert) { + mock_compare_map<torrent::Event>::values.clear(); + }; + +-void mock_init() { +- log_add_group_output(torrent::LOG_MOCK_CALLS, "test_output"); +- mock_clear(true); +-} +- +-void mock_cleanup() { +- mock_clear(false); +-} ++void mock_clear_ignore_assert() { mock_clear(true); } + + namespace torrent { + +diff --git a/test/helpers/mock_function.h b/test/helpers/mock_function.h +index 6c194137..9bc0f162 100644 +--- a/test/helpers/mock_function.h ++++ b/test/helpers/mock_function.h +@@ -11,6 +11,9 @@ + + #include "helpers/mock_compare.h" + ++void mock_clear(bool ignore_assert = false); ++void mock_clear_ignore_assert(); ++ + template<typename R, typename... Args> + struct mock_function_map { + typedef std::tuple<R, Args...> call_type; +@@ -73,9 +76,6 @@ struct mock_function_type<void, Args...> { + static void call_redirect(void* fn, Args... args) { type::redirects.find(fn)->second(args...); } + }; + +-void mock_init(); +-void mock_cleanup(); +- + template<typename R, typename... Args> + bool + mock_cleanup_map(R fn[[gnu::unused]](Args...)) { +diff --git a/test/helpers/progress_listener.cc b/test/helpers/progress_listener.cc +index 7a6ed047..ccd5e66a 100644 +--- a/test/helpers/progress_listener.cc ++++ b/test/helpers/progress_listener.cc +@@ -1,25 +1,60 @@ +-#include "config.h" ++#import "config.h" + +-#include "progress_listener.h" ++#import "progress_listener.h" + +-#include <algorithm> +-#include <iostream> +-#include <iterator> +-#include <numeric> +-#include <stdexcept> +-#include "torrent/utils/log.h" +-#include "torrent/utils/log_buffer.h" ++#import <algorithm> ++#import <iostream> ++#import <iterator> ++#import <numeric> ++#import <stdexcept> ++#import <cppunit/TestCase.h> ++#import <cppunit/TestSuite.h> ++#import "torrent/utils/log.h" ++#import "torrent/utils/log_buffer.h" + + static std::string + get_test_path(const test_list_type& tl) { +- if (tl.size() < 2) ++ if (tl.size() < 3) + return ""; + +- return std::accumulate(std::next(tl.begin()), std::prev(tl.end()), std::string(), [](std::string result, CppUnit::Test* test) { ++ return std::accumulate(std::next(std::next(tl.begin())), std::prev(tl.end()), std::string(), [](std::string result, CppUnit::Test* test) { + return std::move(result) + test->getName() + "::"; + }); + } + ++static int ++get_suite_count(CppUnit::Test *suite) { ++ auto test_suite = dynamic_cast<CppUnit::TestSuite*>(suite); ++ if (test_suite == nullptr) ++ return 0; ++ ++ return std::accumulate(test_suite->getTests().begin(), test_suite->getTests().end(), 0, [](int result, CppUnit::Test* test) { ++ return result + (dynamic_cast<CppUnit::TestSuite*>(test) != nullptr); ++ }); ++} ++ ++static int ++get_case_count(CppUnit::Test *suite) { ++ auto test_suite = dynamic_cast<CppUnit::TestSuite*>(suite); ++ if (test_suite == nullptr) ++ return 0; ++ ++ return std::accumulate(test_suite->getTests().begin(), test_suite->getTests().end(), 0, [](int result, CppUnit::Test* test) { ++ return result + (dynamic_cast<CppUnit::TestCase*>(test) != nullptr); ++ }); ++} ++ ++static int ++get_sub_case_count(CppUnit::Test *suite) { ++ auto test_suite = dynamic_cast<CppUnit::TestSuite*>(suite); ++ if (test_suite == nullptr) ++ return 0; ++ ++ return std::accumulate(test_suite->getTests().begin(), test_suite->getTests().end(), 0, [](int result, CppUnit::Test* test) { ++ return result + get_case_count(test); ++ }); ++} ++ + void + progress_listener::startTest(CppUnit::Test *test) { + std::cout << get_test_path(m_test_path) << test->getName() << std::flush; +@@ -54,8 +89,22 @@ void + progress_listener::startSuite(CppUnit::Test *suite) { + m_test_path.push_back(suite); + +- if (suite->countTestCases() > 0) +- std::cout << std::endl << get_test_path(m_test_path) << suite->getName() << ":" << std::endl; ++ if (suite->countTestCases() == 0) ++ return; ++ ++ if (get_suite_count(suite) == 0) { ++ std::cout << std::endl; ++ return; ++ } ++ ++ if (get_sub_case_count(suite) == 0) ++ return; ++ ++ std::cout << std::endl; ++ std::cout << std::endl; ++ std::cout << std::string(suite->getName().size() + 1, '=') << std::endl; ++ std::cout << suite->getName() << ":" << std::endl; ++ std::cout << std::string(suite->getName().size() + 1, '=') << std::endl; + } + + void +diff --git a/test/helpers/test_fixture.cc b/test/helpers/test_fixture.cc +index 4d8d7214..a435c218 100644 +--- a/test/helpers/test_fixture.cc ++++ b/test/helpers/test_fixture.cc +@@ -2,17 +2,25 @@ +
+ #include "test_fixture.h"
+
++#include "globals.h"
+ #include "torrent/utils/log.h"
++#include "rak/timer.h"
+
+ void
+ test_fixture::setUp() {
+- mock_init();
++ mock_clear_ignore_assert();
+
+- log_add_group_output(torrent::LOG_CONNECTION_BIND, "test_output");
+- log_add_group_output(torrent::LOG_CONNECTION_FD, "test_output");
++ CPPUNIT_ASSERT(torrent::taskScheduler.empty());
++
++ // TODO: Start replacing cachedTime with clock_gettime(CLOCK_REALTIME_COARSE, ...).
++ torrent::cachedTime = rak::timer::current();
++
++ log_add_group_output(torrent::LOG_MOCK_CALLS, "test_output");
+ }
+
+ void
+ test_fixture::tearDown() {
+- mock_cleanup();
++ mock_clear();
++
++ torrent::taskScheduler.clear();
+ }
+diff --git a/test/helpers/utils.h b/test/helpers/utils.h +deleted file mode 100644 +index e81d22eb..00000000 +--- a/test/helpers/utils.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-#ifndef LIBTORRENT_HELPER_UTILS_H +-#define LIBTORRENT_HELPER_UTILS_H +- +-#include <algorithm> +-#include <iostream> +-#include <cppunit/extensions/TestFactoryRegistry.h> +-#include <torrent/utils/log.h> +- +-static void +-dump_failure_log(const failure_type& failure) { +- if (failure.log->empty()) +- return; +- +- std::cout << std::endl << failure.name << std::endl; +- +- // Doesn't print dump messages as log_buffer drops them. +- std::for_each(failure.log->begin(), failure.log->end(), [](const torrent::log_entry& entry) { +- std::cout << entry.timestamp << ' ' << entry.message << '\n'; +- }); +- +- std::cout << std::flush; +-} +- +-static void +-dump_failures(const failure_list_type& failures) { +- if (failures.empty()) +- return; +- +- std::cout << std::endl +- << "=================" << std::endl +- << "Failed Test Logs:" << std::endl +- << "=================" << std::endl; +- +- std::for_each(failures.begin(), failures.end(), [](const failure_type& failure) { +- dump_failure_log(failure); +- }); +- std::cout << std::endl; +-} +- +-static +-void add_tests(CppUnit::TextUi::TestRunner& runner, const char* c_test_names) { +- if (c_test_names == NULL || std::string(c_test_names).empty()) { +- runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); +- return; +- } +- +- const std::string& test_names(c_test_names); +- +- size_t pos = 0; +- size_t next = 0; +- +- while ((next = test_names.find(',', pos)) < test_names.size()) { +- runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(test_names.substr(pos, next - pos)).makeTest()); +- pos = next + 1; +- } +- +- runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(test_names.substr(pos)).makeTest()); +-} +- +-#endif +diff --git a/test/main.cc b/test/main.cc +index 57ae31a2..dd5ca772 100644 +--- a/test/main.cc ++++ b/test/main.cc +@@ -1,27 +1,31 @@ +-#include "config.h" +- +-#include <cstdlib> +-#include <stdexcept> +-#include <signal.h> +-#include <string.h> +-#include <cppunit/BriefTestProgressListener.h> +-#include <cppunit/CompilerOutputter.h> +-#include <cppunit/TestResult.h> +-#include <cppunit/TestResultCollector.h> +-#include <cppunit/extensions/HelperMacros.h> +-#include <cppunit/extensions/TestFactoryRegistry.h> +-#include <cppunit/ui/text/TestRunner.h> ++#import "config.h" ++ ++#import <algorithm> ++#import <cstdlib> ++#import <iostream> ++#import <stdexcept> ++#import <signal.h> ++#import <string.h> ++#import <cppunit/BriefTestProgressListener.h> ++#import <cppunit/CompilerOutputter.h> ++#import <cppunit/TestResult.h> ++#import <cppunit/TestResultCollector.h> ++#import <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/TestFactoryRegistry.h> ++#import <cppunit/ui/text/TestRunner.h> + + #ifdef HAVE_BACKTRACE +-#include <execinfo.h> ++#import <execinfo.h> + #endif + +-#include "helpers/progress_listener.h" +-#include "helpers/utils.h" ++#import "helpers/progress_listener.h" ++#import "torrent/utils/log.h" + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent/net"); + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent/utils"); + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent"); ++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent::tracker_list"); ++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent::tracker_controller"); + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("net"); + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("tracker"); + +@@ -63,6 +67,59 @@ register_signal_handlers() { + } + } + ++static ++void add_tests(CppUnit::TextUi::TestRunner& runner, const char* c_test_names) { ++ if (c_test_names == NULL || std::string(c_test_names).empty()) { ++ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); ++ return; ++ } ++ ++ const std::string& test_names(c_test_names); ++ ++ size_t pos = 0; ++ size_t next = 0; ++ ++ while ((next = test_names.find(',', pos)) < test_names.size()) { ++ auto name = test_names.substr(pos, next - pos); ++ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(name).makeTest()); ++ pos = next + 1; ++ } ++ ++ auto name = test_names.substr(pos); ++ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(name).makeTest()); ++} ++ ++static void ++dump_failure_log(const failure_type& failure) { ++ if (failure.log->empty()) ++ return; ++ ++ std::cout << std::endl << failure.name << std::endl; ++ ++ // Doesn't print dump messages as log_buffer drops them. ++ std::for_each(failure.log->begin(), failure.log->end(), [](const torrent::log_entry& entry) { ++ std::cout << entry.timestamp << ' ' << entry.message << '\n'; ++ }); ++ ++ std::cout << std::flush; ++} ++ ++static void ++dump_failures(const failure_list_type& failures) { ++ if (failures.empty()) ++ return; ++ ++ std::cout << std::endl ++ << "=================" << std::endl ++ << "Failed Test Logs:" << std::endl ++ << "=================" << std::endl; ++ ++ std::for_each(failures.begin(), failures.end(), [](const failure_type& failure) { ++ dump_failure_log(failure); ++ }); ++ std::cout << std::endl; ++} ++ + int main(int argc, char* argv[]) { + register_signal_handlers(); + +diff --git a/test/mock/http.cc b/test/mock/http.cc +new file mode 100755 +index 00000000..df69a961 +--- /dev/null ++++ b/test/mock/http.cc +@@ -0,0 +1,48 @@ ++#import "config.h" ++ ++#import "mock/http.h" ++ ++namespace mock { ++ ++http_getter::http_getter() : ++ m_test_flags(0), ++ m_destroyed_status(nullptr) {} ++ ++http_getter::~http_getter() { ++ if (m_destroyed_status != nullptr) ++ *m_destroyed_status = true; ++} ++ ++void ++http_getter::start() { ++ m_test_flags |= test_flag_active; ++} ++ ++void ++http_getter::close() { ++ m_test_flags &= ~test_flag_active; ++} ++ ++bool ++http_getter::trigger_signal_done() { ++ if (!(m_test_flags & test_flag_active)) ++ return false; ++ ++ m_test_flags &= ~test_flag_active; ++ trigger_done(); ++ ++ return true; ++} ++ ++bool ++http_getter::trigger_signal_failed() { ++ if (!(m_test_flags & test_flag_active)) ++ return false; ++ ++ m_test_flags &= ~test_flag_active; ++ trigger_failed("mock triggered failed"); ++ ++ return true; ++} ++ ++} +diff --git a/test/mock/http.h b/test/mock/http.h +new file mode 100755 +index 00000000..b4c85569 +--- /dev/null ++++ b/test/mock/http.h +@@ -0,0 +1,29 @@ ++#import "torrent/http.h" ++ ++namespace mock { ++ ++class http_getter : public torrent::Http { ++public: ++ static const int test_flag_active = 0x1; ++ ++ http_getter(); ++ ~http_getter() override; ++ ++ void start() override; ++ void close() override; ++ ++ bool trigger_signal_done(); ++ bool trigger_signal_failed(); ++ ++ void set_destroyed_status(bool* status); ++ ++private: ++ int m_test_flags; ++ bool* m_destroyed_status; ++}; ++ ++inline http_getter* create_http_getter() { return new http_getter; } ++ ++inline void http_getter::set_destroyed_status(bool* status) { m_destroyed_status = status; } ++ ++} +diff --git a/test/torrent/test_http.cc b/test/torrent/test_http.cc +index 24ec97b5..a8fb2939 100644 +--- a/test/torrent/test_http.cc ++++ b/test/torrent/test_http.cc +@@ -1,26 +1,27 @@ +-#include "config.h" ++#import "config.h" + +-#include "test_http.h" ++#import "test_http.h" + +-#include <sstream> +-#include "torrent/http.h" ++#import <memory> ++#import <sstream> ++ ++#import "mock/http.h" + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_http, "torrent"); + + #define HTTP_SETUP() \ ++ int done_counter = 0; \ ++ int failed_counter = 0; \ + bool http_destroyed = false; \ + bool stream_destroyed = false; \ + \ +- TestHttp* test_http = new TestHttp(&http_destroyed); \ +- torrent::Http* http = test_http; \ +- std::stringstream* http_stream = new StringStream(&stream_destroyed); \ ++ auto http_getter = new mock::http_getter(); \ ++ auto http_stream = new StringStream(&stream_destroyed); \ + \ +- int done_counter = 0; \ +- int failed_counter = 0; \ +- \ +- http->set_stream(http_stream); \ +- http->signal_done().push_back(std::bind(&increment_value, &done_counter)); \ +- http->signal_failed().push_back(std::bind(&increment_value, &failed_counter)); ++ http_getter->set_destroyed_status(&http_destroyed); \ ++ http_getter->set_stream(http_stream); \ ++ http_getter->signal_done().push_back(std::bind(&increment_value, &done_counter)); \ ++ http_getter->signal_failed().push_back(std::bind(&increment_value, &failed_counter)); + + class StringStream : public std::stringstream { + public: +@@ -30,78 +31,43 @@ private: + bool* m_destroyed; + }; + +-class TestHttp : public torrent::Http { +-public: +- static const int flag_active = 0x1; +- +- TestHttp(bool *destroyed = NULL) : m_flags(0), m_destroyed(destroyed) {} +- virtual ~TestHttp() { if (m_destroyed) *m_destroyed = true; } +- +- virtual void start() { m_flags |= flag_active; } +- virtual void close() { m_flags &= ~flag_active; } +- +- bool trigger_signal_done(); +- bool trigger_signal_failed(); ++static void increment_value(int* value) { (*value)++; } + +-private: +- int m_flags; +- bool* m_destroyed; +-}; ++void ++test_http::test_basic() { ++ mock::http_getter::slot_factory() = std::bind(&mock::create_http_getter); + +-bool +-TestHttp::trigger_signal_done() { +- if (!(m_flags & flag_active)) +- return false; ++ auto http_getter = mock::http_getter::slot_factory()(); ++ auto http_stream = std::make_unique<std::stringstream>(); + +- m_flags &= ~flag_active; +- trigger_done(); +- return true; +-} ++ http_getter->set_url("http://example.com"); ++ CPPUNIT_ASSERT(http_getter->url() == "http://example.com"); + +-bool +-TestHttp::trigger_signal_failed() { +- if (!(m_flags & flag_active)) +- return false; ++ CPPUNIT_ASSERT(http_getter->stream() == NULL); ++ http_getter->set_stream(http_stream.get()); ++ CPPUNIT_ASSERT(http_getter->stream() == http_stream.get()); + +- m_flags &= ~flag_active; +- trigger_failed("We Fail."); +- return true; ++ CPPUNIT_ASSERT(http_getter->timeout() == 0); ++ http_getter->set_timeout(666); ++ CPPUNIT_ASSERT(http_getter->timeout() == 666); + } + +-TestHttp* create_test_http() { return new TestHttp; } +- +-static void increment_value(int* value) { (*value)++; } +- + void +-test_http::test_basic() { +- torrent::Http::slot_factory() = std::bind(&create_test_http); +- +- torrent::Http* http = torrent::Http::slot_factory()(); +- std::stringstream* http_stream = new std::stringstream; +- +- http->set_url("http://example.com"); +- CPPUNIT_ASSERT(http->url() == "http://example.com"); ++test_http::test_flags() { ++ auto http_getter = std::make_unique<mock::http_getter>(); + +- CPPUNIT_ASSERT(http->stream() == NULL); +- http->set_stream(http_stream); +- CPPUNIT_ASSERT(http->stream() == http_stream); ++ CPPUNIT_ASSERT(http_getter->flags() == 0); + +- CPPUNIT_ASSERT(http->timeout() == 0); +- http->set_timeout(666); +- CPPUNIT_ASSERT(http->timeout() == 666); +- +- delete http; +- delete http_stream; ++ // No need to add tests for delete_self/stream as they're going to ++ // be obsolete. + } + + void + test_http::test_done() { + HTTP_SETUP(); +- http->start(); ++ http_getter->start(); + +- CPPUNIT_ASSERT(test_http->trigger_signal_done()); +- +- // Check that we didn't delete... ++ CPPUNIT_ASSERT(http_getter->trigger_signal_done()); + + CPPUNIT_ASSERT(done_counter == 1 && failed_counter == 0); + } +@@ -109,11 +75,9 @@ test_http::test_done() { + void + test_http::test_failure() { + HTTP_SETUP(); +- http->start(); +- +- CPPUNIT_ASSERT(test_http->trigger_signal_failed()); ++ http_getter->start(); + +- // Check that we didn't delete... ++ CPPUNIT_ASSERT(http_getter->trigger_signal_failed()); + + CPPUNIT_ASSERT(done_counter == 0 && failed_counter == 1); + } +@@ -121,26 +85,26 @@ test_http::test_failure() { + void + test_http::test_delete_on_done() { + HTTP_SETUP(); +- http->start(); +- http->set_delete_stream(); ++ http_getter->start(); ++ http_getter->set_delete_stream(); + + CPPUNIT_ASSERT(!stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(test_http->trigger_signal_done()); ++ CPPUNIT_ASSERT(http_getter->trigger_signal_done()); + CPPUNIT_ASSERT(stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(http->stream() == NULL); ++ CPPUNIT_ASSERT(http_getter->stream() == NULL); + + stream_destroyed = false; + http_stream = new StringStream(&stream_destroyed); +- http->set_stream(http_stream); ++ http_getter->set_stream(http_stream); + +- http->start(); +- http->set_delete_self(); ++ http_getter->start(); ++ http_getter->set_delete_self(); + + CPPUNIT_ASSERT(!stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(test_http->trigger_signal_done()); ++ CPPUNIT_ASSERT(http_getter->trigger_signal_done()); + CPPUNIT_ASSERT(stream_destroyed); + CPPUNIT_ASSERT(http_destroyed); + } +@@ -148,27 +112,26 @@ test_http::test_delete_on_done() { + void + test_http::test_delete_on_failure() { + HTTP_SETUP(); +- http->start(); +- http->set_delete_stream(); ++ http_getter->start(); ++ http_getter->set_delete_stream(); + + CPPUNIT_ASSERT(!stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(test_http->trigger_signal_failed()); ++ CPPUNIT_ASSERT(http_getter->trigger_signal_failed()); + CPPUNIT_ASSERT(stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(http->stream() == NULL); ++ CPPUNIT_ASSERT(http_getter->stream() == NULL); + + stream_destroyed = false; + http_stream = new StringStream(&stream_destroyed); +- http->set_stream(http_stream); ++ http_getter->set_stream(http_stream); + +- http->start(); +- http->set_delete_self(); ++ http_getter->start(); ++ http_getter->set_delete_self(); + + CPPUNIT_ASSERT(!stream_destroyed); + CPPUNIT_ASSERT(!http_destroyed); +- CPPUNIT_ASSERT(test_http->trigger_signal_failed()); ++ CPPUNIT_ASSERT(http_getter->trigger_signal_failed()); + CPPUNIT_ASSERT(stream_destroyed); + CPPUNIT_ASSERT(http_destroyed); + } +- +diff --git a/test/torrent/test_http.h b/test/torrent/test_http.h +index f4334646..1443faf9 100644 +--- a/test/torrent/test_http.h ++++ b/test/torrent/test_http.h +@@ -4,6 +4,8 @@ class test_http : public test_fixture { + CPPUNIT_TEST_SUITE(test_http); + + CPPUNIT_TEST(test_basic); ++ CPPUNIT_TEST(test_flags); ++ + CPPUNIT_TEST(test_done); + CPPUNIT_TEST(test_failure); + +@@ -14,10 +16,11 @@ class test_http : public test_fixture { + + public: + void test_basic(); ++ void test_flags(); ++ + void test_done(); + void test_failure(); + + void test_delete_on_done(); + void test_delete_on_failure(); + }; +- +diff --git a/test/torrent/tracker_controller_test.cc b/test/torrent/test_tracker_controller.cc +similarity index 88% +rename from test/torrent/tracker_controller_test.cc +rename to test/torrent/test_tracker_controller.cc +index 9406c99e..0a8db3ea 100644 +--- a/test/torrent/tracker_controller_test.cc ++++ b/test/torrent/test_tracker_controller.cc +@@ -1,15 +1,15 @@ +-#include "config.h" ++#import "config.h" + +-#include <functional> +-#include <iostream> ++#import <functional> ++#import <iostream> + +-#include "rak/priority_queue_default.h" ++#import "rak/priority_queue_default.h" ++#import "globals.h" + +-#include "globals.h" +-#include "tracker_list_test.h" +-#include "tracker_controller_test.h" ++#import "test_tracker_list.h" ++#import "test_tracker_controller.h" + +-CPPUNIT_TEST_SUITE_REGISTRATION(tracker_controller_test); ++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_controller, "torrent::tracker_controller"); + + bool + test_goto_next_timeout(torrent::TrackerController* tracker_controller, uint32_t assumed_timeout, bool is_scrape) { +@@ -49,19 +49,7 @@ test_goto_next_timeout(torrent::TrackerController* tracker_controller, uint32_t + } + + void +-tracker_controller_test::setUp() { +- CPPUNIT_ASSERT(torrent::taskScheduler.empty()); +- +- torrent::cachedTime = rak::timer::current(); +-} +- +-void +-tracker_controller_test::tearDown() { +- torrent::taskScheduler.clear(); +-} +- +-void +-tracker_controller_test::test_basic() { ++test_tracker_controller::test_basic() { + torrent::TrackerController tracker_controller(NULL); + + CPPUNIT_ASSERT(tracker_controller.flags() == 0); +@@ -70,8 +58,9 @@ tracker_controller_test::test_basic() { + } + + void +-tracker_controller_test::test_enable() { +- torrent::TrackerList tracker_list; ++test_tracker_controller::test_enable() { ++ torrent::DownloadInfo download_info; ++ torrent::TrackerList tracker_list(&download_info); + torrent::TrackerController tracker_controller(&tracker_list); + + tracker_controller.enable(); +@@ -81,8 +70,9 @@ tracker_controller_test::test_enable() { + } + + void +-tracker_controller_test::test_requesting() { +- torrent::TrackerList tracker_list; ++test_tracker_controller::test_requesting() { ++ torrent::DownloadInfo download_info; ++ torrent::TrackerList tracker_list(&download_info); + torrent::TrackerController tracker_controller(&tracker_list); + + tracker_controller.enable(); +@@ -98,7 +88,7 @@ tracker_controller_test::test_requesting() { + } + + void +-tracker_controller_test::test_timeout() { ++test_tracker_controller::test_timeout() { + TRACKER_CONTROLLER_SETUP(); + TRACKER_INSERT(0, tracker_0_0); + +@@ -115,7 +105,7 @@ tracker_controller_test::test_timeout() { + } + + void +-tracker_controller_test::test_single_success() { ++test_tracker_controller::test_single_success() { + TEST_SINGLE_BEGIN(); + + tracker_list.send_state_idx(0, 1); +@@ -136,7 +126,7 @@ tracker_controller_test::test_single_success() { + torrent::cachedTime += rak::timer::from_seconds(test_interval); + + void +-tracker_controller_test::test_single_failure() { ++test_tracker_controller::test_single_failure() { + torrent::cachedTime = rak::timer::from_seconds(1 << 20); + TEST_SINGLE_BEGIN(); + +@@ -158,14 +148,14 @@ tracker_controller_test::test_single_failure() { + } + + void +-tracker_controller_test::test_single_disable() { ++test_tracker_controller::test_single_disable() { + TEST_SINGLE_BEGIN(); + tracker_list.send_state_idx(0, 0); + TEST_SINGLE_END(0, 0); + } + + void +-tracker_controller_test::test_send_start() { ++test_tracker_controller::test_send_start() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(start); + +@@ -188,7 +178,7 @@ tracker_controller_test::test_send_start() { + } + + void +-tracker_controller_test::test_send_stop_normal() { ++test_tracker_controller::test_send_stop_normal() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -215,13 +205,14 @@ tracker_controller_test::test_send_stop_normal() { + // send_stop during request and right after start, send stop failed. + + void +-tracker_controller_test::test_send_completed_normal() { ++test_tracker_controller::test_send_completed_normal() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + + CPPUNIT_ASSERT(tracker_controller.task_timeout()->is_queued()); + CPPUNIT_ASSERT(tracker_0_0->trigger_success()); + ++ + tracker_controller.send_completed_event(); + CPPUNIT_ASSERT((tracker_controller.flags() & torrent::TrackerController::mask_send) == torrent::TrackerController::flag_send_completed); + +@@ -240,7 +231,7 @@ tracker_controller_test::test_send_completed_normal() { + } + + void +-tracker_controller_test::test_send_update_normal() { ++test_tracker_controller::test_send_update_normal() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -255,7 +246,7 @@ tracker_controller_test::test_send_update_normal() { + } + + void +-tracker_controller_test::test_send_update_failure() { ++test_tracker_controller::test_send_update_failure() { + torrent::cachedTime = rak::timer::from_seconds(1 << 20); + TEST_SINGLE_BEGIN(); + +@@ -268,7 +259,7 @@ tracker_controller_test::test_send_update_failure() { + } + + void +-tracker_controller_test::test_send_task_timeout() { ++test_tracker_controller::test_send_task_timeout() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -278,7 +269,7 @@ tracker_controller_test::test_send_task_timeout() { + } + + void +-tracker_controller_test::test_send_close_on_enable() { ++test_tracker_controller::test_send_close_on_enable() { + TRACKER_CONTROLLER_SETUP(); + TRACKER_INSERT(0, tracker_0); + TRACKER_INSERT(0, tracker_1); +@@ -299,7 +290,7 @@ tracker_controller_test::test_send_close_on_enable() { + } + + void +-tracker_controller_test::test_multiple_success() { ++test_tracker_controller::test_multiple_success() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -322,7 +313,7 @@ tracker_controller_test::test_multiple_success() { + } + + void +-tracker_controller_test::test_multiple_failure() { ++test_tracker_controller::test_multiple_failure() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -374,13 +365,13 @@ tracker_controller_test::test_multiple_failure() { + } + + void +-tracker_controller_test::test_multiple_cycle() { ++test_tracker_controller::test_multiple_cycle() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + + CPPUNIT_ASSERT(tracker_0_0->trigger_failure()); + CPPUNIT_ASSERT(tracker_0_1->trigger_success()); +- CPPUNIT_ASSERT(tracker_list.front() == tracker_0_1); ++ CPPUNIT_ASSERT(tracker_list.front().get() == tracker_0_1); + + CPPUNIT_ASSERT(test_goto_next_timeout(&tracker_controller, tracker_0_1->normal_interval())); + +@@ -392,7 +383,7 @@ tracker_controller_test::test_multiple_cycle() { + } + + void +-tracker_controller_test::test_multiple_cycle_second_group() { ++test_tracker_controller::test_multiple_cycle_second_group() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -400,17 +391,17 @@ tracker_controller_test::test_multiple_cycle_second_group() { + CPPUNIT_ASSERT(tracker_0_1->trigger_failure()); + CPPUNIT_ASSERT(tracker_1_0->trigger_success()); + +- CPPUNIT_ASSERT(tracker_list[0] == tracker_0_0); +- CPPUNIT_ASSERT(tracker_list[1] == tracker_0_1); +- CPPUNIT_ASSERT(tracker_list[2] == tracker_1_0); +- CPPUNIT_ASSERT(tracker_list[3] == tracker_2_0); +- CPPUNIT_ASSERT(tracker_list[4] == tracker_3_0); ++ CPPUNIT_ASSERT(tracker_list[0].get() == tracker_0_0); ++ CPPUNIT_ASSERT(tracker_list[1].get() == tracker_0_1); ++ CPPUNIT_ASSERT(tracker_list[2].get() == tracker_1_0); ++ CPPUNIT_ASSERT(tracker_list[3].get() == tracker_2_0); ++ CPPUNIT_ASSERT(tracker_list[4].get() == tracker_3_0); + + TEST_MULTIPLE_END(1, 2); + } + + void +-tracker_controller_test::test_multiple_send_stop() { ++test_tracker_controller::test_multiple_send_stop() { + TEST_MULTI3_BEGIN(); + + tracker_list.send_state_idx(1, torrent::Tracker::EVENT_NONE); +@@ -460,7 +451,7 @@ tracker_controller_test::test_multiple_send_stop() { + } + + void +-tracker_controller_test::test_multiple_send_update() { ++test_tracker_controller::test_multiple_send_update() { + TEST_MULTI3_BEGIN(); + + tracker_controller.send_update_event(); +@@ -489,10 +480,11 @@ tracker_controller_test::test_multiple_send_update() { + // The enable/disable tracker functions will poke the tracker + // controller, ensuring the tast timeout gets re-started. + void +-tracker_controller_test::test_timeout_lacking_usable() { ++test_tracker_controller::test_timeout_lacking_usable() { + TEST_MULTI3_BEGIN(); + +- std::for_each(tracker_list.begin(), tracker_list.end(), std::mem_fun(&torrent::Tracker::disable)); ++ std::for_each(tracker_list.begin(), tracker_list.end(), [](auto& v){ v->disable(); }); ++ + CPPUNIT_ASSERT(tracker_controller.task_timeout()->is_queued()); + + CPPUNIT_ASSERT(test_goto_next_timeout(&tracker_controller, 0)); +@@ -518,7 +510,7 @@ tracker_controller_test::test_timeout_lacking_usable() { + } + + void +-tracker_controller_test::test_disable_tracker() { ++test_tracker_controller::test_disable_tracker() { + TEST_SINGLE_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -534,7 +526,7 @@ tracker_controller_test::test_disable_tracker() { + } + + void +-tracker_controller_test::test_new_peers() { ++test_tracker_controller::test_new_peers() { + TRACKER_CONTROLLER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +diff --git a/test/torrent/tracker_controller_test.h b/test/torrent/test_tracker_controller.h +similarity index 94% +rename from test/torrent/tracker_controller_test.h +rename to test/torrent/test_tracker_controller.h +index 80315439..de32f18c 100644 +--- a/test/torrent/tracker_controller_test.h ++++ b/test/torrent/test_tracker_controller.h +@@ -1,9 +1,14 @@ +-#include <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/HelperMacros.h> + +-#include "torrent/tracker_controller.h" ++#import <memory> + +-class tracker_controller_test : public CppUnit::TestFixture { +- CPPUNIT_TEST_SUITE(tracker_controller_test); ++#import "helpers/test_fixture.h" ++ ++#import "torrent/download_info.h" ++#import "torrent/tracker_controller.h" ++ ++class test_tracker_controller : public test_fixture { ++ CPPUNIT_TEST_SUITE(test_tracker_controller); + + CPPUNIT_TEST(test_basic); + CPPUNIT_TEST(test_enable); +@@ -35,9 +40,6 @@ class tracker_controller_test : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE_END(); + + public: +- void setUp(); +- void tearDown(); +- + void test_basic(); + void test_enable(); + void test_disable(); +@@ -69,7 +71,8 @@ public: + }; + + #define TRACKER_CONTROLLER_SETUP() \ +- torrent::TrackerList tracker_list; \ ++ auto download_info = std::make_unique<torrent::DownloadInfo>(); \ ++ torrent::TrackerList tracker_list(download_info.get()); \ + torrent::TrackerController tracker_controller(&tracker_list); \ + \ + int success_counter = 0; \ +diff --git a/test/torrent/tracker_controller_features.cc b/test/torrent/test_tracker_controller_features.cc +similarity index 91% +rename from test/torrent/tracker_controller_features.cc +rename to test/torrent/test_tracker_controller_features.cc +index 0a6a57d6..eabc8d4b 100644 +--- a/test/torrent/tracker_controller_features.cc ++++ b/test/torrent/test_tracker_controller_features.cc +@@ -1,30 +1,18 @@ +-#include "config.h" ++#import "config.h" + +-#include <functional> +-#include <iostream> ++#import <functional> ++#import <iostream> + +-#include "rak/priority_queue_default.h" ++#import "rak/priority_queue_default.h" + +-#include "globals.h" +-#include "tracker_list_test.h" +-#include "tracker_controller_features.h" ++#import "globals.h" ++#import "test_tracker_list.h" ++#import "test_tracker_controller_features.h" + +-CPPUNIT_TEST_SUITE_REGISTRATION(tracker_controller_features); ++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_controller_features, "torrent::tracker_controller"); + + void +-tracker_controller_features::setUp() { +- CPPUNIT_ASSERT(torrent::taskScheduler.empty()); +- +- torrent::cachedTime = rak::timer::current(); +-} +- +-void +-tracker_controller_features::tearDown() { +- torrent::taskScheduler.clear(); +-} +- +-void +-tracker_controller_features::test_requesting_basic() { ++test_tracker_controller_features::test_requesting_basic() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -60,7 +48,7 @@ tracker_controller_features::test_requesting_basic() { + } + + void +-tracker_controller_features::test_requesting_timeout() { ++test_tracker_controller_features::test_requesting_timeout() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(update); + +@@ -90,7 +78,7 @@ tracker_controller_features::test_requesting_timeout() { + } + + void +-tracker_controller_features::test_promiscious_timeout() { ++test_tracker_controller_features::test_promiscious_timeout() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(start); + +@@ -118,7 +106,7 @@ tracker_controller_features::test_promiscious_timeout() { + // situations. This includes fixing old tests. + + void +-tracker_controller_features::test_promiscious_failed() { ++test_tracker_controller_features::test_promiscious_failed() { + TEST_MULTI3_BEGIN(); + TEST_SEND_SINGLE_BEGIN(start); + +@@ -149,7 +137,7 @@ tracker_controller_features::test_promiscious_failed() { + } + + void +-tracker_controller_features::test_scrape_basic() { ++test_tracker_controller_features::test_scrape_basic() { + TEST_GROUP_BEGIN(); + tracker_controller.disable(); + +@@ -191,7 +179,7 @@ tracker_controller_features::test_scrape_basic() { + } + + void +-tracker_controller_features::test_scrape_priority() { ++test_tracker_controller_features::test_scrape_priority() { + TEST_SINGLE_BEGIN(); + CPPUNIT_ASSERT(test_goto_next_timeout(&tracker_controller, 0)); + tracker_0_0->trigger_success(); +@@ -234,7 +222,7 @@ tracker_controller_features::test_scrape_priority() { + } + + void +-tracker_controller_features::test_groups_requesting() { ++test_tracker_controller_features::test_groups_requesting() { + TEST_GROUP_BEGIN(); + TEST_SEND_SINGLE_BEGIN(start); + +@@ -273,7 +261,7 @@ tracker_controller_features::test_groups_requesting() { + } + + void +-tracker_controller_features::test_groups_scrape() { ++test_tracker_controller_features::test_groups_scrape() { + TEST_GROUP_BEGIN(); + tracker_controller.disable(); + +diff --git a/test/torrent/tracker_controller_features.h b/test/torrent/test_tracker_controller_features.h +similarity index 72% +rename from test/torrent/tracker_controller_features.h +rename to test/torrent/test_tracker_controller_features.h +index bbbfec2a..85dc19e8 100644 +--- a/test/torrent/tracker_controller_features.h ++++ b/test/torrent/test_tracker_controller_features.h +@@ -1,9 +1,11 @@ +-#include <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/HelperMacros.h> + +-#include "tracker_controller_test.h" ++#import "helpers/test_fixture.h" + +-class tracker_controller_features : public CppUnit::TestFixture { +- CPPUNIT_TEST_SUITE(tracker_controller_features); ++#import "test_tracker_controller.h" ++ ++class test_tracker_controller_features : public test_fixture { ++ CPPUNIT_TEST_SUITE(test_tracker_controller_features); + + CPPUNIT_TEST(test_requesting_basic); + CPPUNIT_TEST(test_requesting_timeout); +@@ -19,9 +21,6 @@ class tracker_controller_features : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE_END(); + + public: +- void setUp(); +- void tearDown(); +- + void test_requesting_basic(); + void test_requesting_timeout(); + void test_promiscious_timeout(); +diff --git a/test/torrent/tracker_controller_requesting.cc b/test/torrent/test_tracker_controller_requesting.cc +similarity index 80% +rename from test/torrent/tracker_controller_requesting.cc +rename to test/torrent/test_tracker_controller_requesting.cc +index 92e664b3..7fd54f50 100644 +--- a/test/torrent/tracker_controller_requesting.cc ++++ b/test/torrent/test_tracker_controller_requesting.cc +@@ -1,27 +1,15 @@ +-#include "config.h" ++#import "config.h" + +-#include <functional> +-#include <iostream> ++#import <functional> ++#import <iostream> + +-#include "rak/priority_queue_default.h" ++#import "rak/priority_queue_default.h" + +-#include "globals.h" +-#include "tracker_list_test.h" +-#include "tracker_controller_requesting.h" ++#import "globals.h" ++#import "test_tracker_list.h" ++#import "test_tracker_controller_requesting.h" + +-CPPUNIT_TEST_SUITE_REGISTRATION(tracker_controller_requesting); +- +-void +-tracker_controller_requesting::setUp() { +- CPPUNIT_ASSERT(torrent::taskScheduler.empty()); +- +- torrent::cachedTime = rak::timer::current(); +-} +- +-void +-tracker_controller_requesting::tearDown() { +- torrent::taskScheduler.clear(); +-} ++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_controller_requesting, "torrent::tracker_controller"); + + void + do_test_hammering_basic(bool success1, bool success2, bool success3, uint32_t min_interval = 0) { +@@ -69,32 +57,32 @@ do_test_hammering_basic(bool success1, bool success2, bool success3, uint32_t mi + } + + void +-tracker_controller_requesting::test_hammering_basic_success() { ++test_tracker_controller_requesting::test_hammering_basic_success() { + do_test_hammering_basic(true, true, true); + } + + void +-tracker_controller_requesting::test_hammering_basic_success_long_timeout() { ++test_tracker_controller_requesting::test_hammering_basic_success_long_timeout() { + do_test_hammering_basic(true, true, true, 1000); + } + + void +-tracker_controller_requesting::test_hammering_basic_success_short_timeout() { ++test_tracker_controller_requesting::test_hammering_basic_success_short_timeout() { + do_test_hammering_basic(true, true, true, 300); + } + + void +-tracker_controller_requesting::test_hammering_basic_failure() { ++test_tracker_controller_requesting::test_hammering_basic_failure() { + do_test_hammering_basic(true, false, false); + } + + void +-tracker_controller_requesting::test_hammering_basic_failure_long_timeout() { ++test_tracker_controller_requesting::test_hammering_basic_failure_long_timeout() { + do_test_hammering_basic(true, false, false, 1000); + } + + void +-tracker_controller_requesting::test_hammering_basic_failure_short_timeout() { ++test_tracker_controller_requesting::test_hammering_basic_failure_short_timeout() { + do_test_hammering_basic(true, false, false, 300); + } + +@@ -169,20 +157,20 @@ do_test_hammering_multi3(bool success1, bool success2, bool success3, uint32_t m + } + + void +-tracker_controller_requesting::test_hammering_multi_success() { ++test_tracker_controller_requesting::test_hammering_multi_success() { + do_test_hammering_multi3(true, true, true); + } + + void +-tracker_controller_requesting::test_hammering_multi_success_long_timeout() { ++test_tracker_controller_requesting::test_hammering_multi_success_long_timeout() { + do_test_hammering_multi3(true, true, true, 1000); + } + + void +-tracker_controller_requesting::test_hammering_multi_success_short_timeout() { ++test_tracker_controller_requesting::test_hammering_multi_success_short_timeout() { + do_test_hammering_multi3(true, true, true, 300); + } + + void +-tracker_controller_requesting::test_hammering_multi_failure() { ++test_tracker_controller_requesting::test_hammering_multi_failure() { + } +diff --git a/test/torrent/tracker_controller_requesting.h b/test/torrent/test_tracker_controller_requesting.h +similarity index 84% +rename from test/torrent/tracker_controller_requesting.h +rename to test/torrent/test_tracker_controller_requesting.h +index c347ceed..df8ee6d7 100644 +--- a/test/torrent/tracker_controller_requesting.h ++++ b/test/torrent/test_tracker_controller_requesting.h +@@ -1,9 +1,11 @@ +-#include <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/HelperMacros.h> + +-#include "tracker_controller_test.h" ++#import "helpers/test_fixture.h" + +-class tracker_controller_requesting : public CppUnit::TestFixture { +- CPPUNIT_TEST_SUITE(tracker_controller_requesting); ++#import "test_tracker_controller.h" ++ ++class test_tracker_controller_requesting : public test_fixture { ++ CPPUNIT_TEST_SUITE(test_tracker_controller_requesting); + + CPPUNIT_TEST(test_hammering_basic_success); + CPPUNIT_TEST(test_hammering_basic_success_long_timeout); +@@ -16,15 +18,13 @@ class tracker_controller_requesting : public CppUnit::TestFixture { + CPPUNIT_TEST(test_hammering_multi_success_long_timeout); + CPPUNIT_TEST(test_hammering_multi_success_short_timeout); + CPPUNIT_TEST(test_hammering_multi_failure); ++ + // CPPUNIT_TEST(test_hammering_multi_failure_long_timeout); + // CPPUNIT_TEST(test_hammering_multi_failure_short_timeout); + + CPPUNIT_TEST_SUITE_END(); + + public: +- void setUp(); +- void tearDown(); +- + void test_hammering_basic_success(); + void test_hammering_basic_success_long_timeout(); + void test_hammering_basic_success_short_timeout(); +diff --git a/test/torrent/tracker_list_test.cc b/test/torrent/test_tracker_list.cc +similarity index 86% +rename from test/torrent/tracker_list_test.cc +rename to test/torrent/test_tracker_list.cc +index e62383f1..d7d48214 100644 +--- a/test/torrent/tracker_list_test.cc ++++ b/test/torrent/test_tracker_list.cc +@@ -1,27 +1,16 @@ +-#include "config.h" ++#import "config.h" + +-#include "torrent/http.h" +-#include "net/address_list.h" ++#import "globals.h" ++#import "torrent/utils/log.h" ++#import "net/address_list.h" + +-#include "globals.h" +-#include "tracker_list_test.h" ++#import "test_tracker_list.h" ++#import "mock/http.h" + +-CPPUNIT_TEST_SUITE_REGISTRATION(tracker_list_test); ++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_list, "torrent::tracker_list"); + + uint32_t return_new_peers = 0xdeadbeef; + +-class http_get : public torrent::Http { +-public: +- ~http_get() { } +- +- // Start must never throw on bad input. Calling start/stop on an +- // object in the wrong state should throw a torrent::internal_error. +- void start() { } +- void close() { } +-}; +- +-torrent::Http* http_factory() { return new http_get; } +- + bool + TrackerTest::trigger_success(uint32_t new_peers, uint32_t sum_peers) { + torrent::TrackerList::address_list address_list; +@@ -36,17 +25,20 @@ TrackerTest::trigger_success(uint32_t new_peers, uint32_t sum_peers) { + + bool + TrackerTest::trigger_success(torrent::TrackerList::address_list* address_list, uint32_t new_peers) { +- if (parent() == NULL || !is_busy() || !is_open()) ++ if (!is_busy() || !is_open()) + return false; + + m_busy = false; + m_open = !(m_flags & flag_close_on_done); + return_new_peers = new_peers; + +- if (m_latest_event == EVENT_SCRAPE) +- parent()->receive_scrape_success(this); +- else +- parent()->receive_success(this, address_list); ++ if (m_latest_event == EVENT_SCRAPE) { ++ if (m_slot_scrape_success) ++ m_slot_scrape_success(); ++ } else { ++ if (m_slot_success) ++ m_slot_success(address_list); ++ } + + m_requesting_state = -1; + return true; +@@ -54,17 +46,20 @@ TrackerTest::trigger_success(torrent::TrackerList::address_list* address_list, u + + bool + TrackerTest::trigger_failure() { +- if (parent() == NULL || !is_busy() || !is_open()) ++ if (!is_busy() || !is_open()) + return false; + + m_busy = false; + m_open = !(m_flags & flag_close_on_done); + return_new_peers = 0; + +- if (m_latest_event == EVENT_SCRAPE) +- parent()->receive_scrape_failed(this, "failed"); +- else +- parent()->receive_failed(this, "failed"); ++ if (m_latest_event == EVENT_SCRAPE) { ++ if (m_slot_scrape_failure) ++ m_slot_scrape_failure("failed"); ++ } else { ++ if (m_slot_failure) ++ m_slot_failure("failed"); ++ } + + m_requesting_state = -1; + return true; +@@ -72,7 +67,7 @@ TrackerTest::trigger_failure() { + + bool + TrackerTest::trigger_scrape() { +- if (parent() == NULL || !is_busy() || !is_open()) ++ if (!is_busy() || !is_open()) + return false; + + if (m_latest_event != EVENT_SCRAPE) +@@ -82,19 +77,30 @@ TrackerTest::trigger_scrape() { + } + + void +-tracker_list_test::test_basic() { ++test_tracker_list::setUp() { ++ test_fixture::setUp(); ++ ++ // TODO: Refactor tracker logging types: ++ log_add_group_output(torrent::LOG_TRACKER_WARN, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_INFO, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_DEBUG, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_STATE_DEBUG, "test_output"); ++} ++ ++void ++test_tracker_list::test_basic() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +- CPPUNIT_ASSERT(tracker_0 == tracker_list[0]); ++ CPPUNIT_ASSERT(tracker_list.size() == 1); ++ CPPUNIT_ASSERT(tracker_list[0].get() == tracker_0); + +- CPPUNIT_ASSERT(tracker_list[0]->parent() == &tracker_list); + CPPUNIT_ASSERT(std::distance(tracker_list.begin_group(0), tracker_list.end_group(0)) == 1); + CPPUNIT_ASSERT(tracker_list.find_usable(tracker_list.begin()) != tracker_list.end()); + } + + void +-tracker_list_test::test_enable() { ++test_tracker_list::test_enable() { + TRACKER_SETUP(); + int enabled_counter = 0; + int disabled_counter = 0; +@@ -108,7 +114,7 @@ tracker_list_test::test_enable() { + + tracker_0->enable(); tracker_1->enable(); + CPPUNIT_ASSERT(enabled_counter == 2 && disabled_counter == 0); +- ++ + tracker_0->disable(); tracker_1->enable(); + CPPUNIT_ASSERT(enabled_counter == 2 && disabled_counter == 1); + +@@ -121,7 +127,7 @@ tracker_list_test::test_enable() { + } + + void +-tracker_list_test::test_close() { ++test_tracker_list::test_close() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + TRACKER_INSERT(0, tracker_1); +@@ -168,13 +174,14 @@ tracker_list_test::test_close() { + // Test clear. + + void +-tracker_list_test::test_tracker_flags() { ++test_tracker_list::test_tracker_flags() { + TRACKER_SETUP(); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "")); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "", 0)); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "", torrent::Tracker::flag_enabled)); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "", torrent::Tracker::flag_extra_tracker)); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "", torrent::Tracker::flag_enabled | torrent::Tracker::flag_extra_tracker)); ++ ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "")); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "", 0)); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "", torrent::Tracker::flag_enabled)); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "", torrent::Tracker::flag_extra_tracker)); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "", torrent::Tracker::flag_enabled | torrent::Tracker::flag_extra_tracker)); + + CPPUNIT_ASSERT((tracker_list[0]->flags() & torrent::Tracker::mask_base_flags) == torrent::Tracker::flag_enabled); + CPPUNIT_ASSERT((tracker_list[1]->flags() & torrent::Tracker::mask_base_flags) == 0); +@@ -184,12 +191,12 @@ tracker_list_test::test_tracker_flags() { + } + + void +-tracker_list_test::test_find_url() { ++test_tracker_list::test_find_url() { + TRACKER_SETUP(); + +- tracker_list.insert(0, new TrackerTest(&tracker_list, "http://1")); +- tracker_list.insert(0, new TrackerTest(&tracker_list, "http://2")); +- tracker_list.insert(1, new TrackerTest(&tracker_list, "http://3")); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "http://1")); ++ tracker_list.insert(0, new TrackerTest(download_info.get(), "http://2")); ++ tracker_list.insert(1, new TrackerTest(download_info.get(), "http://3")); + + CPPUNIT_ASSERT(tracker_list.find_url("http://") == tracker_list.end()); + +@@ -204,9 +211,9 @@ tracker_list_test::test_find_url() { + } + + void +-tracker_list_test::test_can_scrape() { ++test_tracker_list::test_can_scrape() { + TRACKER_SETUP(); +- torrent::Http::slot_factory() = std::bind(&http_factory); ++ torrent::Http::slot_factory() = std::bind(&mock::create_http_getter); + + tracker_list.insert_url(0, "http://example.com/announce"); + CPPUNIT_ASSERT((tracker_list.back()->flags() & torrent::Tracker::flag_can_scrape)); +@@ -239,7 +246,7 @@ tracker_list_test::test_can_scrape() { + } + + void +-tracker_list_test::test_single_success() { ++test_tracker_list::test_single_success() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +@@ -264,14 +271,14 @@ tracker_list_test::test_single_success() { + CPPUNIT_ASSERT(!tracker_0->is_open()); + CPPUNIT_ASSERT(tracker_0->requesting_state() == -1); + CPPUNIT_ASSERT(tracker_0->latest_event() == torrent::Tracker::EVENT_STARTED); +- ++ + CPPUNIT_ASSERT(success_counter == 1 && failure_counter == 0); + CPPUNIT_ASSERT(tracker_0->success_counter() == 1); + CPPUNIT_ASSERT(tracker_0->failed_counter() == 0); + } + + void +-tracker_list_test::test_single_failure() { ++test_tracker_list::test_single_failure() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +@@ -295,7 +302,7 @@ tracker_list_test::test_single_failure() { + } + + void +-tracker_list_test::test_single_closing() { ++test_tracker_list::test_single_closing() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +@@ -319,7 +326,7 @@ tracker_list_test::test_single_closing() { + } + + void +-tracker_list_test::test_multiple_success() { ++test_tracker_list::test_multiple_success() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0_0); + TRACKER_INSERT(0, tracker_0_1); +@@ -371,10 +378,10 @@ tracker_list_test::test_multiple_success() { + } + + void +-tracker_list_test::test_scrape_success() { ++test_tracker_list::test_scrape_success() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); +- ++ + tracker_0->set_can_scrape(); + tracker_list.send_scrape(tracker_0); + +@@ -391,7 +398,7 @@ tracker_list_test::test_scrape_success() { + CPPUNIT_ASSERT(!tracker_0->is_open()); + CPPUNIT_ASSERT(tracker_0->requesting_state() == -1); + CPPUNIT_ASSERT(tracker_0->latest_event() == torrent::Tracker::EVENT_SCRAPE); +- ++ + CPPUNIT_ASSERT(success_counter == 0 && failure_counter == 0); + CPPUNIT_ASSERT(scrape_success_counter == 1 && scrape_failure_counter == 0); + CPPUNIT_ASSERT(tracker_0->success_counter() == 0); +@@ -400,10 +407,10 @@ tracker_list_test::test_scrape_success() { + } + + void +-tracker_list_test::test_scrape_failure() { ++test_tracker_list::test_scrape_failure() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); +- ++ + tracker_0->set_can_scrape(); + tracker_list.send_scrape(tracker_0); + +@@ -413,7 +420,7 @@ tracker_list_test::test_scrape_failure() { + CPPUNIT_ASSERT(!tracker_0->is_open()); + CPPUNIT_ASSERT(tracker_0->requesting_state() == -1); + CPPUNIT_ASSERT(tracker_0->latest_event() == torrent::Tracker::EVENT_SCRAPE); +- ++ + CPPUNIT_ASSERT(success_counter == 0 && failure_counter == 0); + CPPUNIT_ASSERT(scrape_success_counter == 0 && scrape_failure_counter == 1); + CPPUNIT_ASSERT(tracker_0->success_counter() == 0); +@@ -441,7 +448,7 @@ check_has_active_in_group(const torrent::TrackerList* tracker_list, const char* + } + + void +-tracker_list_test::test_has_active() { ++test_tracker_list::test_has_active() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + TRACKER_INSERT(0, tracker_1); +diff --git a/test/torrent/tracker_list_test.h b/test/torrent/test_tracker_list.h +similarity index 89% +rename from test/torrent/tracker_list_test.h +rename to test/torrent/test_tracker_list.h +index 39fc7c19..57c368f0 100644 +--- a/test/torrent/tracker_list_test.h ++++ b/test/torrent/test_tracker_list.h +@@ -1,10 +1,17 @@ +-#include <torrent/tracker.h> +-#include <torrent/tracker_list.h> +-#include <rak/timer.h> +-#include <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/HelperMacros.h> ++ ++#import <memory> ++ ++#import "helpers/test_fixture.h" ++ ++#import "torrent/download_info.h" ++#import "torrent/tracker.h" ++#import "torrent/tracker_list.h" ++#import "rak/timer.h" ++ ++class test_tracker_list : public test_fixture { ++ CPPUNIT_TEST_SUITE(test_tracker_list); + +-class tracker_list_test : public CppUnit::TestFixture { +- CPPUNIT_TEST_SUITE(tracker_list_test); + CPPUNIT_TEST(test_basic); + CPPUNIT_TEST(test_enable); + CPPUNIT_TEST(test_close); +@@ -23,11 +30,11 @@ class tracker_list_test : public CppUnit::TestFixture { + CPPUNIT_TEST(test_scrape_failure); + + CPPUNIT_TEST(test_has_active); ++ + CPPUNIT_TEST_SUITE_END(); + + public: +- void setUp() {} +- void tearDown() {} ++ void setUp(); + + void test_basic(); + void test_enable(); +@@ -49,14 +56,15 @@ public: + void test_has_active(); + }; + ++// TODO: Move. + class TrackerTest : public torrent::Tracker { + public: + static const int flag_close_on_done = max_flag_size << 0; + static const int flag_scrape_on_success = max_flag_size << 1; + + // TODO: Clean up tracker related enums. +- TrackerTest(torrent::TrackerList* parent, const std::string& url, int flags = torrent::Tracker::flag_enabled) : +- torrent::Tracker(parent, url, flags), ++ TrackerTest(torrent::DownloadInfo* info, const std::string& url, int flags = torrent::Tracker::flag_enabled) : ++ torrent::Tracker(info, url, flags), + m_busy(false), + m_open(false), + m_requesting_state(-1) { m_flags |= flag_close_on_done; } +@@ -105,18 +113,21 @@ inline unsigned int increment_value_uint(int* value) { (*value)++; return return + bool check_has_active_in_group(const torrent::TrackerList* tracker_list, const char* states, bool scrape); + + #define TRACKER_SETUP() \ +- torrent::TrackerList tracker_list; \ ++ auto download_info = std::make_unique<torrent::DownloadInfo>(); \ ++ torrent::TrackerList tracker_list(download_info.get()); \ ++ \ + int success_counter = 0; \ + int failure_counter = 0; \ + int scrape_success_counter = 0; \ + int scrape_failure_counter = 0; \ ++ \ + tracker_list.slot_success() = std::bind(&increment_value_uint, &success_counter); \ + tracker_list.slot_failure() = std::bind(&increment_value_void, &failure_counter); \ + tracker_list.slot_scrape_success() = std::bind(&increment_value_void, &scrape_success_counter); \ + tracker_list.slot_scrape_failure() = std::bind(&increment_value_void, &scrape_failure_counter); + +-#define TRACKER_INSERT(group, name) \ +- TrackerTest* name = new TrackerTest(&tracker_list, ""); \ ++#define TRACKER_INSERT(group, name) \ ++ TrackerTest* name = new TrackerTest(download_info.get(), ""); \ + tracker_list.insert(group, name); + + #define TEST_TRACKER_IS_BUSY(tracker, state) \ +diff --git a/test/torrent/tracker_list_features_test.cc b/test/torrent/test_tracker_list_features.cc +similarity index 88% +rename from test/torrent/tracker_list_features_test.cc +rename to test/torrent/test_tracker_list_features.cc +index 5257b1a7..99c0850c 100644 +--- a/test/torrent/tracker_list_features_test.cc ++++ b/test/torrent/test_tracker_list_features.cc +@@ -1,29 +1,30 @@ +-#include "config.h" ++#import "config.h" + +-#include <functional> ++#import <functional> + +-#include "torrent/http.h" +-#include "net/address_list.h" ++#import "torrent/http.h" ++#import "torrent/utils/log.h" ++#import "net/address_list.h" + +-#include "globals.h" +-#include "tracker_list_test.h" +-#include "tracker_list_features_test.h" ++#import "globals.h" ++#import "test_tracker_list.h" ++#import "test_tracker_list_features.h" + +-CPPUNIT_TEST_SUITE_REGISTRATION(tracker_list_features_test); ++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_list_features, "torrent::tracker_list"); + + void +-tracker_list_features_test::setUp() { +- CPPUNIT_ASSERT(torrent::taskScheduler.empty()); +- +- torrent::cachedTime = rak::timer::current(); +-} +- +-void +-tracker_list_features_test::tearDown() { ++test_tracker_list_features::setUp() { ++ test_fixture::setUp(); ++ ++ // TODO: Refactor tracker logging types: ++ log_add_group_output(torrent::LOG_TRACKER_WARN, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_INFO, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_DEBUG, "test_output"); ++ log_add_group_output(torrent::LOG_TRACKER_STATE_DEBUG, "test_output"); + } + + void +-tracker_list_features_test::test_new_peers() { ++test_tracker_list_features::test_new_peers() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + +@@ -51,7 +52,7 @@ tracker_list_features_test::test_new_peers() { + // test has_active, and then clean up TrackerManager. + + void +-tracker_list_features_test::test_has_active() { ++test_tracker_list_features::test_has_active() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0_0); + TRACKER_INSERT(0, tracker_0_1); +@@ -84,7 +85,7 @@ tracker_list_features_test::test_has_active() { + } + + void +-tracker_list_features_test::test_find_next_to_request() { ++test_tracker_list_features::test_find_next_to_request() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + TRACKER_INSERT(0, tracker_1); +@@ -123,7 +124,7 @@ tracker_list_features_test::test_find_next_to_request() { + } + + void +-tracker_list_features_test::test_find_next_to_request_groups() { ++test_tracker_list_features::test_find_next_to_request_groups() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0); + TRACKER_INSERT(0, tracker_1); +@@ -146,7 +147,7 @@ tracker_list_features_test::test_find_next_to_request_groups() { + } + + void +-tracker_list_features_test::test_count_active() { ++test_tracker_list_features::test_count_active() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_0_0); + TRACKER_INSERT(0, tracker_0_1); +@@ -193,7 +194,7 @@ verify_did_internal_error(std::function<void ()> func, bool should_throw) { + } + + void +-tracker_list_features_test::test_request_safeguard() { ++test_tracker_list_features::test_request_safeguard() { + TRACKER_SETUP(); + TRACKER_INSERT(0, tracker_1); + TRACKER_INSERT(0, tracker_2); +diff --git a/test/torrent/tracker_list_features_test.h b/test/torrent/test_tracker_list_features.h +similarity index 72% +rename from test/torrent/tracker_list_features_test.h +rename to test/torrent/test_tracker_list_features.h +index e1c70486..cfe3965a 100644 +--- a/test/torrent/tracker_list_features_test.h ++++ b/test/torrent/test_tracker_list_features.h +@@ -1,7 +1,10 @@ +-#include <cppunit/extensions/HelperMacros.h> ++#import <cppunit/extensions/HelperMacros.h> ++ ++#import "helpers/test_fixture.h" ++ ++class test_tracker_list_features : public test_fixture { ++ CPPUNIT_TEST_SUITE(test_tracker_list_features); + +-class tracker_list_features_test : public CppUnit::TestFixture { +- CPPUNIT_TEST_SUITE(tracker_list_features_test); + CPPUNIT_TEST(test_new_peers); + CPPUNIT_TEST(test_has_active); + CPPUNIT_TEST(test_find_next_to_request); +@@ -9,11 +12,11 @@ class tracker_list_features_test : public CppUnit::TestFixture { + CPPUNIT_TEST(test_count_active); + + CPPUNIT_TEST(test_request_safeguard); ++ + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); +- void tearDown(); + + void test_new_peers(); + void test_has_active(); +diff --git a/test/torrent/tracker_timeout_test.cc b/test/torrent/tracker_timeout_test.cc +index cd060006..399fc973 100644 +--- a/test/torrent/tracker_timeout_test.cc ++++ b/test/torrent/tracker_timeout_test.cc +@@ -6,7 +6,7 @@ + #include "rak/priority_queue_default.h" + + #include "globals.h" +-#include "tracker_list_test.h" ++#include "test_tracker_list.h" + #include "tracker_timeout_test.h" + + CPPUNIT_TEST_SUITE_REGISTRATION(tracker_timeout_test); +diff --git a/test/tracker/test_tracker_http.cc b/test/tracker/test_tracker_http.cc +index 399d00d5..46813be7 100644 +--- a/test/tracker/test_tracker_http.cc ++++ b/test/tracker/test_tracker_http.cc +@@ -1,11 +1,27 @@ +-#include "config.h" ++#import "config.h" + +-#include "test_tracker_http.h" ++#import "test_tracker_http.h" + +-#include "tracker/tracker_http.h" ++#import "mock/http.h" ++#import "torrent/tracker_list.h" ++#import "tracker/tracker_http.h" + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_http, "tracker"); + + void + test_tracker_http::test_basic() { ++ // TODO: Replace TrackerList parameter with slots, then write these tests. ++ ++ ++ // torrent::Http::slot_factory() = std::bind(&test::tracker_http::create_http_getter); ++ ++ // std::unique_ptr<torrent::TrackerList> tracker_list(new torrent::TrackerList()); ++ ++ // tracker_list->slot_success() = std::bind(&test::tracker_http::controller_receive_success, std::placeholders::_1, std::placeholders::_2); ++ // tracker_list->slot_failure() = std::bind(&test::tracker_http::controller_receive_failure, std::placeholders::_1, std::placeholders::_2); ++ // tracker_list->slot_scrape_success() = std::bind(&test::tracker_http::controller_receive_scrape, std::placeholders::_1); ++ // tracker_list->slot_tracker_enabled() = std::bind(&test::tracker_http::controller_receive_tracker_enabled, std::placeholders::_1); ++ // tracker_list->slot_tracker_disabled() = std::bind(&test::tracker_http::controller_receive_tracker_disabled, std::placeholders::_1); ++ ++ // tracker_list->insert_url(0, "http://example.com/announce", false); + } +diff --git a/test/tracker/test_tracker_http.h b/test/tracker/test_tracker_http.h +index ab11a8f7..97ee2194 100644 +--- a/test/tracker/test_tracker_http.h ++++ b/test/tracker/test_tracker_http.h +@@ -1,10 +1,10 @@ +-#include "helpers/test_fixture.h" +- +-#include "torrent/utils/thread_base.h" ++#import "helpers/test_fixture.h" + + class test_tracker_http : public test_fixture { + CPPUNIT_TEST_SUITE(test_tracker_http); ++ + CPPUNIT_TEST(test_basic); ++ + CPPUNIT_TEST_SUITE_END(); + + public: |