diff mbox series

[AUH] libtorrent: upgrading to 1 SUCCEEDED

Message ID 0101018b96bedeff-ef74b4dd-cfbe-4927-ab9a-b72a3ae10603-000000@us-west-2.amazonses.com
State New
Headers show
Series [AUH] libtorrent: upgrading to 1 SUCCEEDED | expand

Commit Message

auh@yoctoproject.org Nov. 3, 2023, 7:52 p.m. UTC
Hello,

this email is a notification from the Auto Upgrade Helper
that the automatic attempt to upgrade the recipe *libtorrent* to *1* has Succeeded.

Next steps:
    - apply the patch: git am 0001-libtorrent-upgrade-0.13.8-1.patch
    - check the changes to upstream patches and summarize them in the commit message,
    - compile an image that contains the package
    - perform some basic sanity tests
    - amend the patch and sign it off: git commit -s --reset-author --amend
    - send it to the appropriate mailing list

Alternatively, if you believe the recipe should not be upgraded at this time,
you can fill RECIPE_NO_UPDATE_REASON in respective recipe file so that
automatic upgrades would no longer be attempted.

Please review the attached files for further information and build/update failures.
Any problem please file a bug at https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Automated%20Update%20Handler

Regards,
The Upgrade Helper

-- >8 --
From 83a38bc5603090648c65b7bd15a471401a083a6e Mon Sep 17 00:00:00 2001
From: Upgrade Helper <auh@yoctoproject.org>
Date: Fri, 3 Nov 2023 15:07:47 +0000
Subject: [PATCH] libtorrent: upgrade 0.13.8 -> 1

---
 ...issue-with-gcc-v6.x-and-empty-CXXFLA.patch |   44 +
 ...c-v6.x-fix-for-empty-CXXFLAGS-See-10.patch |   56 +
 ...pace-to-fmt-str-in-log_gz_file_write.patch |   27 +
 ...ncement-11IPv4-filter-enhancement-Cl.patch |  379 +
 ...extents-test-to-pass-TravisCI-See-11.patch |   47 +
 .../0006-Bumped-version-to-0.13.7.patch       |   30 +
 .../0007-Added-support-for-openssl-1.1.patch  |  105 +
 ...nstead-of-AC_RUN-to-check-for-execin.patch |   24 +
 ...-to-prevent-unnecessary-kqueue-check.patch |   46 +
 ...failed-tracker-bencode-parsing-See-9.patch |   58 +
 ...when-displaying-info-on-failed-track.patch |   60 +
 ...tch-to-C-11-MRT-RNG-for-random-bytes.patch |   45 +
 ...m_ipv6_socket-attribute-which-led-to.patch |   45 +
 ...-creation-AF_INET6-failes-initialize.patch |   27 +
 ...hub.com-rakshasa-rtorrent-issues-731.patch |   29 +
 ...ottle.min_peers-settings-in-rtorrent.patch |   40 +
 .../0017-increase-piece-length-max.patch      |   22 +
 .../0018-Set-max-piece-size-512mb.patch       |   22 +
 .../0019-Fixed-compiler-warning.patch         |   22 +
 ..._GNU_SOURCE-to-fallocate-test.-neheb.patch |   74 +
 ...-Fixed-diffie-hellman-implementation.patch |  293 +
 ...sed-max-timeout-for-tracker-requests.patch |   64 +
 ...-Close-log-files-when-reusing-a-name.patch |  123 +
 .../0024-Bumped-to-version-0.13.8.patch       |   30 +
 ...-be-appended-rather-than-overwritten.patch |  109 +
 ...nd-function.-Added-append-parameter-.patch |  101 +
 ...kport-changes-from-feature-bind.-200.patch | 7365 +++++++++++++++++
 ...ibtorrent.pc.in-add-Libs.Private-202.patch |   26 +
 ...fy-missing-quickly-renamed-files-203.patch |   27 +
 .../0030-Fix-compiler-warnings.-204.patch     |  470 ++
 ...-log-format-so-GCC-can-check-it.-205.patch |   33 +
 ...e-make-script-to-optimize-build.-206.patch |  843 ++
 .../0033-Refactor-make-process.-207.patch     | 2710 ++++++
 ...0034-Changes-automake-required-files.patch |   22 +
 ...placed-custom-execinfo-autoconf-test.patch |   48 +
 ...option-to-disable-pthread_setname_np.patch |  135 +
 ...37-Improved-backtrace-error-checking.patch |  594 ++
 ...-multiple-connections-from-NAT-not-w.patch |  199 +
 ...disable-execinfo-option-to-configure.patch |   32 +
 .../libtorrent/0040-Detect-ip-address.patch   |  457 +
 .../libtorrent/0041-Added-ipv6-options.patch  |   85 +
 .../0042-Removed-obsolete-files.patch         |  444 +
 ...Updated-and-cleaned-up-automake.-224.patch | 2979 +++++++
 .../libtorrent/0044-Create-FUNDING.yml.patch  |   29 +
 .../libtorrent/libtorrent_git.bb              |   51 +-
 45 files changed, 18468 insertions(+), 3 deletions(-)
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0001-Fix-compilation-issue-with-gcc-v6.x-and-empty-CXXFLA.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0002-Modfiy-gcc-v6.x-fix-for-empty-CXXFLAGS-See-10.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0003-Add-space-to-fmt-str-in-log_gz_file_write.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0004-IPv4-filter-enhancement-11IPv4-filter-enhancement-Cl.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0005-Disable-extents-test-to-pass-TravisCI-See-11.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0006-Bumped-version-to-0.13.7.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0007-Added-support-for-openssl-1.1.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0008-Use-AC_COMPILE-instead-of-AC_RUN-to-check-for-execin.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0009-Modify-configure-to-prevent-unnecessary-kqueue-check.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0010-Display-info-on-failed-tracker-bencode-parsing-See-9.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0011-Strip-tags-also-when-displaying-info-on-failed-track.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0012-Switch-to-C-11-MRT-RNG-for-random-bytes.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0013-Prevent-loss-of-m_ipv6_socket-attribute-which-led-to.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0014-If-during-socket-creation-AF_INET6-failes-initialize.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0015-Fixes-https-github.com-rakshasa-rtorrent-issues-731.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0016-Fix-honoring-throttle.min_peers-settings-in-rtorrent.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0017-increase-piece-length-max.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0018-Set-max-piece-size-512mb.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0019-Fixed-compiler-warning.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0020-Added-_GNU_SOURCE-to-fallocate-test.-neheb.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0021-Fixed-diffie-hellman-implementation.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0022-Increased-max-timeout-for-tracker-requests.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0023-Close-log-files-when-reusing-a-name.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0024-Bumped-to-version-0.13.8.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0025-Allow-logs-to-be-appended-rather-than-overwritten.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0026-Removed-log-append-function.-Added-append-parameter-.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0027-Backport-changes-from-feature-bind.-200.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0028-libtorrent.pc.in-add-Libs.Private-202.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0029-Fix-for-inotify-missing-quickly-renamed-files-203.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0030-Fix-compiler-warnings.-204.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0031-Fix-log-format-so-GCC-can-check-it.-205.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0032-Consolidate-make-script-to-optimize-build.-206.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0033-Refactor-make-process.-207.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0034-Changes-automake-required-files.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0035-Replaced-custom-execinfo-autoconf-test.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0036-Added-option-to-disable-pthread_setname_np.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0037-Improved-backtrace-error-checking.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0038-Fixed-issue-with-multiple-connections-from-NAT-not-w.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0039-Added-disable-execinfo-option-to-configure.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0040-Detect-ip-address.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0041-Added-ipv6-options.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0042-Removed-obsolete-files.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0043-Updated-and-cleaned-up-automake.-224.patch
 create mode 100644 meta-oe/recipes-connectivity/libtorrent/libtorrent/0044-Create-FUNDING.yml.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0001-Fix-compilation-issue-with-gcc-v6.x-and-empty-CXXFLA.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0001-Fix-compilation-issue-with-gcc-v6.x-and-empty-CXXFLA.patch
new file mode 100644
index 000000000..bc4bade51
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0001-Fix-compilation-issue-with-gcc-v6.x-and-empty-CXXFLA.patch
@@ -0,0 +1,44 @@ 
+From c2b119de0e66fb047bb20e445ac8e25824448858 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Sun, 30 Jul 2017 20:34:47 +0100
+Subject: [PATCH] Fix compilation issue with gcc v6.x and empty CXXFLAGS (See
+ #10)
+
+---
+ configure.ac            |  1 +
+ scripts/rak_compiler.m4 | 13 +++++++++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 65e34872..2f29e3f9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -28,6 +28,7 @@ AC_C_BIGENDIAN(
+     AC_MSG_ERROR([Could not determine endianness])
+ )
+ 
++RAK_CHECK_CXXFLAGS
+ RAK_ENABLE_DEBUG
+ RAK_ENABLE_EXTRA_DEBUG
+ RAK_ENABLE_WERROR
+diff --git a/scripts/rak_compiler.m4 b/scripts/rak_compiler.m4
+index 39bd19a7..87871abf 100644
+--- a/scripts/rak_compiler.m4
++++ b/scripts/rak_compiler.m4
+@@ -1,3 +1,16 @@
++AC_DEFUN([RAK_CHECK_CXXFLAGS], [
++
++  AC_MSG_CHECKING([for user-defined CXXFLAGS])
++
++  if test -n "$CXXFLAGS"; then
++    AC_MSG_RESULT([user-defined "$CXXFLAGS"])
++  else
++    CXXFLAGS="-O2"
++    AC_MSG_RESULT([default "$CXXFLAGS"])
++  fi
++])
++
++
+ AC_DEFUN([RAK_ENABLE_DEBUG], [
+   AC_ARG_ENABLE(debug,
+     AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]),
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0002-Modfiy-gcc-v6.x-fix-for-empty-CXXFLAGS-See-10.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0002-Modfiy-gcc-v6.x-fix-for-empty-CXXFLAGS-See-10.patch
new file mode 100644
index 000000000..532b65a7c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0002-Modfiy-gcc-v6.x-fix-for-empty-CXXFLAGS-See-10.patch
@@ -0,0 +1,56 @@ 
+From 8229218dff1105e9fb2bb2c7510910a0db98f3ef Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Wed, 2 Aug 2017 12:48:27 +0100
+Subject: [PATCH] Modfiy gcc v6.x fix for empty CXXFLAGS (See #10)
+
+---
+ configure.ac            |  1 +
+ scripts/rak_compiler.m4 | 21 +++++++++++++++++----
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 2f29e3f9..a6df6b80 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -28,6 +28,7 @@ AC_C_BIGENDIAN(
+     AC_MSG_ERROR([Could not determine endianness])
+ )
+ 
++RAK_CHECK_CFLAGS
+ RAK_CHECK_CXXFLAGS
+ RAK_ENABLE_DEBUG
+ RAK_ENABLE_EXTRA_DEBUG
+diff --git a/scripts/rak_compiler.m4 b/scripts/rak_compiler.m4
+index 87871abf..9a361bed 100644
+--- a/scripts/rak_compiler.m4
++++ b/scripts/rak_compiler.m4
+@@ -1,12 +1,25 @@
++AC_DEFUN([RAK_CHECK_CFLAGS], [
++
++  AC_MSG_CHECKING([for user-defined CFLAGS])
++
++  if test "$CFLAGS" = ""; then
++    unset CFLAGS
++    AC_MSG_RESULT([undefined])
++  else
++    AC_MSG_RESULT([user-defined "$CFLAGS"])
++  fi
++])
++
++
+ AC_DEFUN([RAK_CHECK_CXXFLAGS], [
+ 
+   AC_MSG_CHECKING([for user-defined CXXFLAGS])
+ 
+-  if test -n "$CXXFLAGS"; then
+-    AC_MSG_RESULT([user-defined "$CXXFLAGS"])
++  if test "$CXXFLAGS" = ""; then
++    unset CXXFLAGS
++    AC_MSG_RESULT([undefined])
+   else
+-    CXXFLAGS="-O2"
+-    AC_MSG_RESULT([default "$CXXFLAGS"])
++    AC_MSG_RESULT([user-defined "$CXXFLAGS"])
+   fi
+ ])
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0003-Add-space-to-fmt-str-in-log_gz_file_write.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0003-Add-space-to-fmt-str-in-log_gz_file_write.patch
new file mode 100644
index 000000000..810b4d4ca
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0003-Add-space-to-fmt-str-in-log_gz_file_write.patch
@@ -0,0 +1,27 @@ 
+From 48635a0fdb06b8572809dc54c630109db1e6e85c Mon Sep 17 00:00:00 2001
+From: Matt Traudt <sirmatt@ksu.edu>
+Date: Mon, 20 Nov 2017 15:22:51 -0500
+Subject: [PATCH] Add space to fmt str in log_gz_file_write
+
+Without this space, the log level identifier ('D', 'I', etc.)
+would be right next to actual content.
+
+Before: <timestamp> Depoll->pcb(17): Open event.
+After: <timestamp> D epoll->pcb(17): Open event.
+---
+ src/torrent/utils/log.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index 646d36e3..58b563a6 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -381,7 +381,7 @@ log_gz_file_write(std::shared_ptr<log_gz_output>& outfile, const char* data, siz
+ 
+   // Normal groups are nul-terminated strings.
+   if (group >= 0) {
+-    const char* fmt = (group >= LOG_NON_CASCADING) ? ("%" PRIi32 " ") : ("%" PRIi32 " %c");
++    const char* fmt = (group >= LOG_NON_CASCADING) ? ("%" PRIi32 " ") : ("%" PRIi32 " %c ");
+ 
+     int buffer_length = snprintf(buffer, 64, fmt,
+                                  cachedTime.seconds(),
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0004-IPv4-filter-enhancement-11IPv4-filter-enhancement-Cl.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0004-IPv4-filter-enhancement-11IPv4-filter-enhancement-Cl.patch
new file mode 100644
index 000000000..c7a01409d
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0004-IPv4-filter-enhancement-11IPv4-filter-enhancement-Cl.patch
@@ -0,0 +1,379 @@ 
+From facd1b78071e315a2e5ee4992d3545dae4290e07 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Sun, 10 Dec 2017 18:51:32 +0000
+Subject: [PATCH] IPv4 filter enhancement #11IPv4 filter enhancement (Closes
+ #11)
+
+---
+ src/torrent/peer/peer_list.cc |  23 ++-
+ src/torrent/peer/peer_list.h  |   2 +-
+ src/torrent/utils/extents.h   | 267 ++++++++++++++--------------------
+ 3 files changed, 134 insertions(+), 158 deletions(-)
+
+diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc
+index 23ca651a..aa60939a 100644
+--- a/src/torrent/peer/peer_list.cc
++++ b/src/torrent/peer/peer_list.cc
+@@ -146,7 +146,11 @@ PeerList::insert_address(const sockaddr* sa, int flags) {
+ 
+   PeerInfo* peerInfo = new PeerInfo(sa);
+   peerInfo->set_listen_port(address->port());
+-  peerInfo->set_flags(m_ipv4_table.at(address->sa_inet()->address_h()) & PeerInfo::mask_ip_table);
++  uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h();
++
++  // IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called
++  if(m_ipv4_table.defined(host_byte_order_ipv4_addr))
++    peerInfo->set_flags(m_ipv4_table.at(host_byte_order_ipv4_addr) & PeerInfo::mask_ip_table);
+   
+   manager->client_list()->retrieve_unknown(&peerInfo->mutable_client_info());
+ 
+@@ -264,12 +268,25 @@ PeerList::connected(const sockaddr* sa, int flags) {
+       !socket_address_key::is_comparable_sockaddr(sa))
+     return NULL;
+ 
+-  int filter_value = m_ipv4_table.at(address->sa_inet()->address_h());
++  uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h();
++  int filter_value = 0;
++
++  // IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called
++  if(m_ipv4_table.defined(host_byte_order_ipv4_addr))
++    filter_value = m_ipv4_table.at(host_byte_order_ipv4_addr);
+ 
+   // We should also remove any PeerInfo objects already for this
+   // address.
+-  if ((filter_value & PeerInfo::flag_unwanted))
++  if ((filter_value & PeerInfo::flag_unwanted)) {
++    char ipv4_str[INET_ADDRSTRLEN];
++    uint32_t net_order_addr = htonl(host_byte_order_ipv4_addr);
++
++    inet_ntop(AF_INET, &net_order_addr, ipv4_str, INET_ADDRSTRLEN);
++
++    lt_log_print(LOG_PEER_INFO, "Peer %s is unwanted: preventing connection", ipv4_str);
++
+     return NULL;
++  }
+ 
+   PeerInfo* peerInfo;
+   range_type range = base_type::equal_range(sock_key);
+diff --git a/src/torrent/peer/peer_list.h b/src/torrent/peer/peer_list.h
+index a3b409cb..4c2f707d 100644
+--- a/src/torrent/peer/peer_list.h
++++ b/src/torrent/peer/peer_list.h
+@@ -46,7 +46,7 @@ namespace torrent {
+ 
+ class DownloadInfo;
+ 
+-typedef extents<uint32_t, int, 32, 256, 8> ipv4_table;
++typedef extents<uint32_t, int> ipv4_table;
+ 
+ class LIBTORRENT_EXPORT PeerList : private std::multimap<socket_address_key, PeerInfo*> {
+ public:
+diff --git a/src/torrent/utils/extents.h b/src/torrent/utils/extents.h
+index 8ec1e600..c2b887b1 100644
+--- a/src/torrent/utils/extents.h
++++ b/src/torrent/utils/extents.h
+@@ -37,191 +37,150 @@
+ #ifndef LIBTORRENT_UTILS_EXTENTS_H
+ #define LIBTORRENT_UTILS_EXTENTS_H
+ 
+-#include lt_tr1_array
+ 
+-#include <algorithm>
++#include <map>
++#include <stdexcept>
+ 
+ namespace torrent {
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-struct extents_base {
+-  typedef Key                          key_type;
+-  typedef std::pair<Key, Key>          range_type;
+-  typedef std::pair<extents_base*, Tp> mapped_type;
+-  typedef Tp                           mapped_value_type;
+-
+-  typedef std::array<mapped_type, TableSize> table_type;
+-  
+-  extents_base(key_type pos, unsigned int mb, mapped_value_type val);
+-  extents_base(extents_base* parent, typename table_type::const_iterator itr);
+-  ~extents_base();
+-
+-  bool         is_divisible(key_type key) const { return key % mask_bits == 0; }
+-  bool         is_leaf_branch() const           { return mask_bits == 0; }
+-  bool         is_equal_range(key_type first, key_type last, const mapped_value_type& val) const;
+-
+-  unsigned int sizeof_data() const;
+-
+-  typename table_type::iterator       partition_at(key_type key)           { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); }
+-  typename table_type::const_iterator partition_at(key_type key) const     { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); }
+-
+-  unsigned int mask_distance(unsigned int mb) { return (~(~key_type() << mb) >> mask_bits); }
+-
+-  key_type     partition_pos(typename table_type::const_iterator part) const { return position + (std::distance(table.begin(), part) << mask_bits); }
+-
+-  void         insert(key_type pos, unsigned int mb, const mapped_value_type& val);
+-
+-  const mapped_value_type& at(key_type key) const;
+-
+-  unsigned int mask_bits;
+-  key_type     position;
+-  table_type   table;
+-};
+-
+-template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
+-class extents : private extents_base<Key, Tp, TableSize, TableBits> {
++template <class Address, class Value, class Compare=std::less<Address> >
++class extents {
+ public:
+-  typedef extents_base<Key, Tp, TableSize, TableBits> base_type;
+-
+-  typedef typename base_type::key_type          key_type;
+-  typedef base_type                             value_type;
+-  typedef typename base_type::range_type        range_type;
+-  typedef typename base_type::mapped_type       mapped_type;
+-  typedef typename base_type::mapped_value_type mapped_value_type;
+-  typedef typename base_type::table_type        table_type;
+-
+-  static const key_type mask_bits  = MaskBits;
+-  static const key_type table_bits = TableBits;
+-  static const key_type table_size = TableSize;
+-
+-  using base_type::at;
+-  using base_type::sizeof_data;
++  typedef Address                                  key_type;           // start address
++  typedef Value                                    mapped_value_type;  // The value mapped to the ip range
++  typedef std::pair<Address, Value>                mapped_type;        // End address, value mapped to ip range
++  typedef std::map<key_type, mapped_type, Compare> range_map_type;     // The map itself 
+ 
+   extents();
++  ~extents();
+ 
+-  bool is_equal_range(key_type first, key_type last, const mapped_value_type& val) const;
+-
+-  void insert(key_type pos, unsigned int mb, const mapped_value_type& val);
++  void              insert(key_type address_start, key_type address_end, mapped_value_type value);
++  bool              defined(key_type address_start, key_type address_end);
++  bool              defined(key_type address);
++  key_type          get_matching_key(key_type address_start, key_type address_end); // throws error on not defined. test with defined() 
++  mapped_value_type at(key_type address_start, key_type address_end);               // throws error on not defined. test with defined() 
++  mapped_value_type at(key_type address);                                           // throws error on not defined. test with defined()
++  unsigned int      sizeof_data() const;
+ 
+-  base_type* data() { return this; }
++  range_map_type    range_map;
+ };
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-extents_base<Key, Tp, TableSize, TableBits>::extents_base(key_type pos, unsigned int mb, mapped_value_type val) :
+-  mask_bits(mb), position(pos) {
+-  std::fill(table.begin(), table.end(), mapped_type(NULL, mapped_value_type()));
++///////////////////////////////////////
++// CONSTRUCTOR [PLACEHOLDER]
++///////////////////////////////////////
++template <class Address, class Value, class Compare >
++extents<Address, Value, Compare>::extents() {
++  //nothing to do
++  return;
+ }
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-extents_base<Key, Tp, TableSize, TableBits>::extents_base(extents_base* parent, typename table_type::const_iterator itr) :
+-  mask_bits(parent->mask_bits - TableBits), position(parent->partition_pos(itr)) {
+-  std::fill(table.begin(), table.end(), mapped_type(NULL, itr->second));
++///////////////////////////////////////
++// DESTRUCTOR [PLACEHOLDER]
++///////////////////////////////////////
++template <class Address, class Value, class Compare >
++extents<Address, Value, Compare>::~extents() {
++  //nothing to do. map destructor can handle cleanup. 
++  return;
+ }
+ 
+-template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
+-extents<Key, Tp, MaskBits, TableSize, TableBits>::extents() :
+-  base_type(key_type(), mask_bits - table_bits, mapped_value_type())
+-{
+-}
++//////////////////////////////////////////////////////////////////////////////////
++// INSERT O(log N) assuming no overlapping ranges
++/////////////////////////////////////////////////////////////////////////////////
++template <class Address, class Value, class Compare >
++void extents<Address, Value, Compare>::insert(key_type address_start, key_type address_end, mapped_value_type value) {
++  //we allow overlap ranges though not 100% overlap but only if mapped values are the same.  first remove any overlap range that has a different value.
++  typename range_map_type::iterator iter = range_map.upper_bound(address_start); 
++  if( iter != range_map.begin() ) { iter--; } 
++  bool ignore_due_to_total_overlap = false;
++  while( iter->first <= address_end && iter != range_map.end() ) {
++    key_type delete_key = iter->first;
++    bool do_delete_due_to_overlap        =  iter->first <= address_end && (iter->second).first >= address_start && (iter->second).second != value;
++    bool do_delete_due_to_total_overlap  =  address_start <= iter->first && address_end >= (iter->second).first;
++    iter++;
++    if(do_delete_due_to_overlap || do_delete_due_to_total_overlap) {
++      range_map.erase (delete_key);
++    }
++    else {
++      ignore_due_to_total_overlap = ignore_due_to_total_overlap || ( iter->first <= address_start && (iter->second).first >= address_end );
++    }
++  }
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-extents_base<Key, Tp, TableSize, TableBits>::~extents_base() {
+-  for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++)
+-    delete itr->first;
++  if(!ignore_due_to_total_overlap) {
++    mapped_type entry;
++    entry.first = address_end;
++    entry.second = value;
++    range_map.insert( std::pair<key_type,mapped_type>(address_start, entry) );
++  }
+ }
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-unsigned int
+-extents_base<Key, Tp, TableSize, TableBits>::sizeof_data() const {
+-  unsigned int sum = sizeof(*this);
+-
+-  for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++)
+-    if (itr->first != NULL)
+-      sum += itr->first->sizeof_data();
+-
+-  return sum;
++//////////////////////////////////////////////////////////////////////
++// DEFINED  O(log N) assuming no overlapping ranges
++//////////////////////////////////////////////////////////////////////
++template <class Address, class Value, class Compare >
++bool extents<Address, Value, Compare>::defined(key_type address_start, key_type address_end) {
++  bool defined = false;
++  typename range_map_type::iterator iter = range_map.upper_bound(address_start);
++  if( iter != range_map.begin() ) { iter--; } 
++  while( iter->first <= address_end && !defined && iter != range_map.end() ) {
++    defined = iter->first <= address_end && (iter->second).first >= address_start;
++    iter++;
++  }
++  return defined;
+ }
+-
+-template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
+-void
+-extents<Key, Tp, MaskBits, TableSize, TableBits>::insert(key_type pos, unsigned int mb, const mapped_value_type& val) {
+-  key_type mask = ~key_type() << mb;
+-
+-  base_type::insert(pos & mask, mb, val);
++template <class Address, class Value, class Compare >
++bool extents<Address, Value, Compare>::defined(key_type address) {
++  return defined(address, address);
+ }
+ 
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-void
+-extents_base<Key, Tp, TableSize, TableBits>::insert(key_type pos, unsigned int mb, const mapped_value_type& val) {
+-  // RESTRICTED
+-  typename table_type::iterator first = partition_at(pos);
+-  typename table_type::iterator last = partition_at(pos) + mask_distance(mb) + 1;
+-
+-  if (mb < mask_bits) {
+-    if (first->first == NULL)
+-      first->first = new extents_base(this, first);
++//////////////////////////////////////////////////////////////////////
++// GET_MATCHING_KEY  O(log N) assuming no overlapping ranges
++//////////////////////////////////////////////////////////////////////
++template <class Address, class Value, class Compare >
++typename extents<Address, Value, Compare>::key_type extents<Address, Value, Compare>::get_matching_key(key_type address_start, key_type address_end) {
++  key_type key;
++  bool defined = false;
++  typename range_map_type::iterator iter = range_map.upper_bound(address_start);
++  if( iter != range_map.begin() ) { iter--; } 
++  while( iter->first <= address_end && !defined && iter != range_map.end() ) {
++    defined = iter->first <= address_end && (iter->second).first >= address_start;
++    if(defined)
++      key = iter->first;
+     
+-    first->first->insert(pos, mb, val);
+-    return;
++    iter++;
+   }
+-
+-  while (first != last) {
+-    if (first->first != NULL) {
+-      delete first->first;
+-      first->first = NULL;
+-    }
+-    
+-    (first++)->second = val;
++  // this will cause exception to be thrown 
++  if(!defined) {
++    std::out_of_range e("nothing defined for specified key");
++    throw e;
+   }
++  return key;
+ }
+ 
+-template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
+-bool
+-extents<Key, Tp, MaskBits, TableSize, TableBits>::is_equal_range(key_type first, key_type last, const mapped_value_type& val) const {
+-  // RESTRICTED
+-  first = std::max(first, key_type());
+-  last = std::min(last, key_type() + (~key_type() >> (sizeof(key_type) * 8 - MaskBits)));
+-
+-  if (first <= last)
+-    return base_type::is_equal_range(first, last, val);
+-  else
+-    return true;
++//////////////////////////////////////////////////////////////////////
++// AT  O(log N) assuming no overlapping ranges
++//////////////////////////////////////////////////////////////////////
++template <class Address, class Value, class Compare >
++typename extents<Address, Value, Compare>::mapped_value_type extents<Address, Value, Compare>::at(key_type address_start, key_type address_end) {
++  key_type key = get_matching_key(address_start, address_end);
++  mapped_type entry = range_map.at(key);
++  return entry.second;
+ }
+-
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-bool
+-extents_base<Key, Tp, TableSize, TableBits>::is_equal_range(key_type key_first, key_type key_last, const mapped_value_type& val) const {
+-  // RESTRICTED
+-  typename table_type::const_iterator first = partition_at(key_first);
+-  typename table_type::const_iterator last = partition_at(key_last) + 1;
+-
+-  do {
+-    //    std::cout << "shift_amount " << key_first << ' ' << key_last << std::endl;
+-
+-    if (first->first == NULL && val != first->second)
+-      return false;
+-
+-    if (first->first != NULL && !first->first->is_equal_range(std::max(key_first, partition_pos(first)),
+-                                                              std::min(key_last, partition_pos(first + 1) - 1), val))
+-      return false;
+-
+-  } while (++first != last);
+-
+-  return true;
++template <class Address, class Value, class Compare >
++typename extents<Address, Value, Compare>::mapped_value_type extents<Address, Value, Compare>::at(key_type address) {
++  return at(address, address);
+ }
+ 
+-// Assumes 'key' is within the range of the range.
+-template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
+-const typename extents_base<Key, Tp, TableSize, TableBits>::mapped_value_type&
+-extents_base<Key, Tp, TableSize, TableBits>::at(key_type key) const {
+-  typename table_type::const_iterator itr = partition_at(key);
+-
+-  while (itr->first != NULL)
+-    itr = itr->first->partition_at(key);
+-
+-  return itr->second;
++//////////////////////////////////////////////////////////////////////
++// SIZEOF_DATA  O(1)
++//////////////////////////////////////////////////////////////////////
++template <class Address, class Value, class Compare >
++unsigned int extents<Address, Value, Compare>::sizeof_data() const {
++  // we don't know overhead on map, so this won't be accurate.  just estimate.
++  unsigned int entry_size = sizeof(key_type) + sizeof(mapped_type);
++  return entry_size * range_map.size();
+ }
+ 
++
+ }
+ 
+ #endif
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0005-Disable-extents-test-to-pass-TravisCI-See-11.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0005-Disable-extents-test-to-pass-TravisCI-See-11.patch
new file mode 100644
index 000000000..45f92524f
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0005-Disable-extents-test-to-pass-TravisCI-See-11.patch
@@ -0,0 +1,47 @@ 
+From 4a5ed3897e772c75929b376b08985d844898b619 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Tue, 12 Dec 2017 15:19:51 +0000
+Subject: [PATCH] Disable extents test to pass TravisCI (See #11)
+
+---
+ test/torrent/utils/test_extents.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/test/torrent/utils/test_extents.cc b/test/torrent/utils/test_extents.cc
+index 6ac5a57d..d6b8d11d 100644
+--- a/test/torrent/utils/test_extents.cc
++++ b/test/torrent/utils/test_extents.cc
+@@ -16,10 +16,11 @@ void
+ ExtentsTest::tearDown() {
+ }
+ 
+-typedef torrent::extents<uint32_t, int, 8, 16, 4> extent_type_1;
++//typedef torrent::extents<uint32_t, int, 8, 16, 4> extent_type_1;
++typedef torrent::extents<uint32_t, int> extent_type_1;
+ 
+ // typedef torrent::extents<uint32_t, int, 0, 256, 16> extent_type_3;
+-
++/*
+ template <typename Extent>
+ bool
+ verify_extent_data(Extent& extent, const uint32_t* idx, const int* val) {
+@@ -46,11 +47,11 @@ static const int      val_basic_1[] = {1, 0, 1};
+ 
+ // static const uint32_t idx_basic_2[] = {0, 1, 16, 255, 256, 256};
+ // static const int      val_basic_2[] = {1, 0, 2, 1};
+-
++*/
+ void
+ ExtentsTest::test_basic() {
+   extent_type_1 extent_1;
+-
++/*
+   // Test empty.
+   CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_empty, val_empty));
+ 
+@@ -68,4 +69,5 @@ ExtentsTest::test_basic() {
+   // extent_1.insert(38, 3, 2);
+ 
+   // CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_basic_2, val_basic_2));
++*/
+ }
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0006-Bumped-version-to-0.13.7.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0006-Bumped-version-to-0.13.7.patch
new file mode 100644
index 000000000..645cf0f99
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0006-Bumped-version-to-0.13.7.patch
@@ -0,0 +1,30 @@ 
+From da7db7db29a8488e29d3b0f02906c5db379d4b6d Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Thu, 7 Jun 2018 13:18:03 +0900
+Subject: [PATCH] Bumped version to 0.13.7.
+
+---
+ configure.ac | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index a6df6b80..5b1ea237 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,12 +1,12 @@
+-AC_INIT(libtorrent, 0.13.6, sundell.software@gmail.com)
++AC_INIT(libtorrent, 0.13.7, sundell.software@gmail.com)
+ 
+ LT_INIT([disable-static])
+ 
+ dnl Find a better way to do this
+-AC_DEFINE(PEER_NAME, "-lt0D60-", Identifier that is part of the default peer id)
+-AC_DEFINE(PEER_VERSION, "lt\x0D\x60", 4 byte client and version identifier for DHT)
++AC_DEFINE(PEER_NAME, "-lt0D70-", Identifier that is part of the default peer id)
++AC_DEFINE(PEER_VERSION, "lt\x0D\x70", 4 byte client and version identifier for DHT)
+ 
+-LIBTORRENT_CURRENT=19
++LIBTORRENT_CURRENT=20
+ LIBTORRENT_REVISION=0
+ LIBTORRENT_AGE=0
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0007-Added-support-for-openssl-1.1.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0007-Added-support-for-openssl-1.1.patch
new file mode 100644
index 000000000..eaec545bb
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0007-Added-support-for-openssl-1.1.patch
@@ -0,0 +1,105 @@ 
+From dbf6abfd6f905b9218465d15eebec7eedaaed6b0 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Tue, 20 Dec 2016 19:51:02 +0900
+Subject: [PATCH] Added support for openssl 1.1.
+
+---
+ configure.ac                |  4 ++++
+ src/utils/diffie_hellman.cc | 36 ++++++++++++++++++++++++++++++++++--
+ 2 files changed, 38 insertions(+), 2 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 5b1ea237..b885714d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -71,12 +71,15 @@ AC_ARG_ENABLE(openssl,
+   [  --disable-openssl       Don't use OpenSSL's SHA1 implementation.],
+   [
+     if test "$enableval" = "yes"; then
++dnl move to scripts.
+       PKG_CHECK_MODULES(OPENSSL, libcrypto,
+         CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
+         LIBS="$LIBS $OPENSSL_LIBS")
+ 
+       AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
+       AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
++      AC_CHECK_LIB([crypto], [DH_set0_pqg], [AC_DEFINE(USE_OPENSSL_1_1, 1, Using OpenSSL 1.1.)])
++
+     else
+       AC_DEFINE(USE_NSS_SHA, 1, Using Mozilla's SHA1 implementation.)
+     fi
+@@ -87,6 +90,7 @@ AC_ARG_ENABLE(openssl,
+ 
+     AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
+     AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
++    AC_CHECK_LIB([crypto], [DH_set0_pqg], [AC_DEFINE(USE_OPENSSL_1_1, 1, Using OpenSSL 1.1.)])
+   ]
+ )
+ 
+diff --git a/src/utils/diffie_hellman.cc b/src/utils/diffie_hellman.cc
+index aa653d45..7ec13165 100644
+--- a/src/utils/diffie_hellman.cc
++++ b/src/utils/diffie_hellman.cc
+@@ -54,11 +54,23 @@ DiffieHellman::DiffieHellman(const unsigned char *prime, int primeLength,
+   m_secret(NULL), m_size(0) {
+ 
+ #ifdef USE_OPENSSL
++
+   m_dh = DH_new();
++
++#ifdef USE_OPENSSL_1_1
++  BIGNUM * const dh_p = BN_bin2bn(prime, primeLength, NULL);
++  BIGNUM * const dh_g = BN_bin2bn(generator, generatorLength, NULL);
++
++  if (dh_p == NULL || dh_g == NULL ||
++      !DH_set0_pqg(m_dh, dh_p, NULL, dh_g))
++	  throw internal_error("Could not generate Diffie-Hellman parameters");
++#else
+   m_dh->p = BN_bin2bn(prime, primeLength, NULL);
+   m_dh->g = BN_bin2bn(generator, generatorLength, NULL);
++#endif
+ 
+   DH_generate_key(m_dh);
++
+ #else
+   throw internal_error("Compiled without encryption support.");
+ #endif
+@@ -74,7 +86,19 @@ DiffieHellman::~DiffieHellman() {
+ bool
+ DiffieHellman::is_valid() const {
+ #ifdef USE_OPENSSL
++  if (m_dh == NULL)
++    return false;
++
++#ifdef USE_OPENSSL_1_1
++  const BIGNUM *pub_key;
++
++  DH_get0_key(m_dh, &pub_key, NULL);
++
++  return pub_key != NULL;
++#else
+   return m_dh != NULL && m_dh->pub_key != NULL;
++#endif
++
+ #else
+   return false;
+ #endif
+@@ -103,8 +127,16 @@ DiffieHellman::store_pub_key(unsigned char* dest, unsigned int length) {
+ #ifdef USE_OPENSSL
+   std::memset(dest, 0, length);
+ 
+-  if ((int)length >= BN_num_bytes(m_dh->pub_key))
+-    BN_bn2bin(m_dh->pub_key, dest + length - BN_num_bytes(m_dh->pub_key));
++  const BIGNUM *pub_key;
++
++#ifdef USE_OPENSSL_1_1
++  DH_get0_key(m_dh, &pub_key, NULL);
++#else
++  pub_key = m_dh->pub_key;
++#endif
++
++  if ((int)length >= BN_num_bytes(pub_key))
++    BN_bn2bin(pub_key, dest + length - BN_num_bytes(pub_key));
+ #endif
+ }
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0008-Use-AC_COMPILE-instead-of-AC_RUN-to-check-for-execin.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0008-Use-AC_COMPILE-instead-of-AC_RUN-to-check-for-execin.patch
new file mode 100644
index 000000000..6625fb55c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0008-Use-AC_COMPILE-instead-of-AC_RUN-to-check-for-execin.patch
@@ -0,0 +1,24 @@ 
+From c2ec5e0fb8ce7a0df513b5f4086e23d92049ef0e Mon Sep 17 00:00:00 2001
+From: Stephen Shkardoon <ss23@ss23.geek.nz>
+Date: Mon, 25 Jun 2018 20:05:18 +1200
+Subject: [PATCH] Use AC_COMPILE instead of AC_RUN to check for execinfo.h
+
+This way enables cross compiling, since we don't need to run anything
+during the configure script.
+---
+ scripts/common.m4 | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/scripts/common.m4 b/scripts/common.m4
+index ff023928..b6d051f5 100644
+--- a/scripts/common.m4
++++ b/scripts/common.m4
+@@ -153,7 +153,7 @@ dnl   Need to fix this so that it uses the stuff defined by the system.
+ AC_DEFUN([TORRENT_CHECK_EXECINFO], [
+   AC_MSG_CHECKING(for execinfo.h)
+ 
+-  AC_RUN_IFELSE([AC_LANG_SOURCE([
++  AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+       #include <execinfo.h>
+       int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
+       ])],
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0009-Modify-configure-to-prevent-unnecessary-kqueue-check.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0009-Modify-configure-to-prevent-unnecessary-kqueue-check.patch
new file mode 100644
index 000000000..974f992de
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0009-Modify-configure-to-prevent-unnecessary-kqueue-check.patch
@@ -0,0 +1,46 @@ 
+From b0fb874a8921fa4ba2ea0923d779fae8f70c82b1 Mon Sep 17 00:00:00 2001
+From: Stephen Shkardoon <ss23@ss23.geek.nz>
+Date: Thu, 21 Jun 2018 14:38:30 +1200
+Subject: [PATCH] Modify configure to prevent unnecessary kqueue checks
+
+By only running the TORRENT_CHECK_KQUEUE_SOCKET_ONLY check if kqueue support
+is already detected, we increase the number of platforms that we can
+cross compile on.
+Otherwise, the cross compilation fails due to TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+using AC_RUN_IFELSE, which fails during cross compilation.
+---
+ scripts/checks.m4 | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/scripts/checks.m4 b/scripts/checks.m4
+index 8d77fc5e..c9333561 100644
+--- a/scripts/checks.m4
++++ b/scripts/checks.m4
+@@ -88,6 +88,7 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
+     [
+       AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
+       AC_MSG_RESULT(yes)
++      TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ], [
+       AC_MSG_RESULT(no)
+     ])
+@@ -137,7 +138,6 @@ AC_DEFUN([TORRENT_WITH_KQUEUE], [
+     [
+         if test "$withval" = "yes"; then
+           TORRENT_CHECK_KQUEUE
+-          TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+         fi
+     ])
+ ])
+@@ -149,11 +149,9 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_KQUEUE
+-        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+       fi
+     ], [
+         TORRENT_CHECK_KQUEUE
+-        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ])
+ ])
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0010-Display-info-on-failed-tracker-bencode-parsing-See-9.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0010-Display-info-on-failed-tracker-bencode-parsing-See-9.patch
new file mode 100644
index 000000000..562cdae7a
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0010-Display-info-on-failed-tracker-bencode-parsing-See-9.patch
@@ -0,0 +1,58 @@ 
+From 4ff83fc53b2c7462b02f804ee20414d85944e3c9 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Sun, 14 May 2017 19:36:09 +0100
+Subject: [PATCH] Display info on failed tracker bencode parsing (See #9)
+
+---
+ rak/string_manip.h          | 20 ++++++++++++++++++++
+ src/tracker/tracker_http.cc |  6 ++++--
+ 2 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/rak/string_manip.h b/rak/string_manip.h
+index f8d3f590..68614d2a 100644
+--- a/rak/string_manip.h
++++ b/rak/string_manip.h
+@@ -371,6 +371,26 @@ is_all_name(const Sequence& src) {
+   return is_all_name(src.begin(), src.end());
+ }
+ 
++template <typename Iterator>
++std::string
++sanitize(Iterator first, Iterator last) {
++  std::string dest;
++  for (; first != last; ++first) {
++    if (std::isprint(*first) && *first != '\r' && *first != '\n' && *first != '\t')
++      dest += *first;
++    else
++      dest += " ";
++  }
++
++  return dest;
++}
++
++template <typename Sequence>
++std::string
++sanitize(const Sequence& src) {
++    return trim(sanitize(src.begin(), src.end()));
++}
++
+ }
+ 
+ #endif
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index 553f922c..b6d9e0ac 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -288,8 +288,10 @@ TrackerHttp::receive_done() {
+   Object b;
+   *m_data >> b;
+ 
+-  if (m_data->fail())
+-    return receive_failed("Could not parse bencoded data");
++  if (m_data->fail()) {
++    std::string dump = m_data->str();
++    return receive_failed("Could not parse bencoded data: " + rak::sanitize(dump).substr(0,99));
++  }
+ 
+   if (!b.is_map())
+     return receive_failed("Root not a bencoded map");
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0011-Strip-tags-also-when-displaying-info-on-failed-track.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0011-Strip-tags-also-when-displaying-info-on-failed-track.patch
new file mode 100644
index 000000000..7a8c9aa5a
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0011-Strip-tags-also-when-displaying-info-on-failed-track.patch
@@ -0,0 +1,60 @@ 
+From 2f197be69057f793d29272b90300f74d0b588d51 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Mon, 15 May 2017 19:24:33 +0100
+Subject: [PATCH] Strip tags also when displaying info on failed tracker
+ bencode parsing (See #9)
+
+---
+ rak/string_manip.h          | 25 +++++++++++++++++++++++++
+ src/tracker/tracker_http.cc |  2 +-
+ 2 files changed, 26 insertions(+), 1 deletion(-)
+
+diff --git a/rak/string_manip.h b/rak/string_manip.h
+index 68614d2a..ae867c98 100644
+--- a/rak/string_manip.h
++++ b/rak/string_manip.h
+@@ -391,6 +391,31 @@ sanitize(const Sequence& src) {
+     return trim(sanitize(src.begin(), src.end()));
+ }
+ 
++template <typename Iterator>
++std::string striptags(Iterator first, Iterator last) {
++  bool copychar = true;
++  std::string dest;
++
++  for (; first != last; ++first) {
++    if (std::isprint(*first) && *first == '<') {
++      copychar = false;
++    } else if (std::isprint(*first) && *first == '>') {
++      copychar = true;
++      continue;
++    }
++
++    if (copychar)
++      dest += *first;
++  }
++
++  return dest;
++}
++
++template <typename Sequence>
++std::string striptags(const Sequence& src) {
++    return striptags(src.begin(), src.end());
++}
++
+ }
+ 
+ #endif
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index b6d9e0ac..eefe5a17 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -290,7 +290,7 @@ TrackerHttp::receive_done() {
+ 
+   if (m_data->fail()) {
+     std::string dump = m_data->str();
+-    return receive_failed("Could not parse bencoded data: " + rak::sanitize(dump).substr(0,99));
++    return receive_failed("Could not parse bencoded data: " + rak::sanitize(rak::striptags(dump)).substr(0,99));
+   }
+ 
+   if (!b.is_map())
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0012-Switch-to-C-11-MRT-RNG-for-random-bytes.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0012-Switch-to-C-11-MRT-RNG-for-random-bytes.patch
new file mode 100644
index 000000000..f4776247d
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0012-Switch-to-C-11-MRT-RNG-for-random-bytes.patch
@@ -0,0 +1,45 @@ 
+From 0e86289a8bb5672781e508683bb28aebf9995127 Mon Sep 17 00:00:00 2001
+From: lps-rocks <admin@lps.rocks>
+Date: Mon, 4 Mar 2019 05:03:47 -0500
+Subject: [PATCH] Switch to C++11 MRT RNG for random bytes
+
+Switching to a better RNG for generating strings will prevent the common peerID collisions the rTorrent client has been seeing for YEARS in #440 and #318.
+---
+ rak/string_manip.h | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/rak/string_manip.h b/rak/string_manip.h
+index ae867c98..1a09c377 100644
+--- a/rak/string_manip.h
++++ b/rak/string_manip.h
+@@ -39,9 +39,13 @@
+ 
+ #include <algorithm>
+ #include <cctype>
++#include <climits>
+ #include <cstdlib>
++#include <functional>
+ #include <iterator>
+ #include <locale>
++#include <random>
++
+ 
+ namespace rak {
+ 
+@@ -312,11 +316,13 @@ transform_hex_str(const Sequence& seq) {
+ template <typename Sequence>
+ Sequence
+ generate_random(size_t length) {
++  std::random_device rd;
++  std::mt19937 mt(rd());
++  using bytes_randomizer = std::independent_bits_engine<std::mt19937, CHAR_BIT, uint8_t>;
++  bytes_randomizer bytes(mt);
+   Sequence s;
+   s.reserve(length);
+-
+-  std::generate_n(std::back_inserter(s), length, &::random);
+-
++  std::generate_n(std::back_inserter(s), length, std::ref(bytes));
+   return s;
+ }
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0013-Prevent-loss-of-m_ipv6_socket-attribute-which-led-to.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0013-Prevent-loss-of-m_ipv6_socket-attribute-which-led-to.patch
new file mode 100644
index 000000000..1d4cc3e33
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0013-Prevent-loss-of-m_ipv6_socket-attribute-which-led-to.patch
@@ -0,0 +1,45 @@ 
+From bf35c5f3d4e458a671fdc3c382f4fa06ecaeb119 Mon Sep 17 00:00:00 2001
+From: Vladyslav Movchan <vladislav.movchan@gmail.com>
+Date: Sat, 3 Nov 2018 19:52:56 +0200
+Subject: [PATCH] Prevent loss of 'm_ipv6_socket' attribute which led to
+ execution of setsockopt(..., IPPROTO_IP, IP_TOS, ...) on IPv6 socket
+
+---
+ src/net/socket_fd.cc | 4 ++--
+ src/net/socket_fd.h  | 1 +
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc
+index 54cb6ded..f04059f6 100644
+--- a/src/net/socket_fd.cc
++++ b/src/net/socket_fd.cc
+@@ -251,7 +251,7 @@ SocketFd::accept(rak::socket_address* sa) {
+   socklen_t len = sizeof(rak::socket_address);
+ 
+   if (sa == NULL) {
+-    return SocketFd(::accept(m_fd, NULL, &len));
++    return SocketFd(::accept(m_fd, NULL, &len), m_ipv6_socket);
+   }
+ 
+   int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
+@@ -260,7 +260,7 @@ SocketFd::accept(rak::socket_address* sa) {
+     *sa = sa->sa_inet6()->normalize_address();
+   }
+ 
+-  return SocketFd(fd);
++  return SocketFd(fd, m_ipv6_socket);
+ }
+ 
+ // unsigned int
+diff --git a/src/net/socket_fd.h b/src/net/socket_fd.h
+index ca765e88..2329b4e9 100644
+--- a/src/net/socket_fd.h
++++ b/src/net/socket_fd.h
+@@ -51,6 +51,7 @@ public:
+ 
+   SocketFd() : m_fd(-1) {}
+   explicit SocketFd(int fd) : m_fd(fd) {}
++  SocketFd(int fd, bool ipv6_socket) : m_fd(fd), m_ipv6_socket(ipv6_socket) {}
+ 
+   bool                is_valid() const                        { return m_fd >= 0; }
+   
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0014-If-during-socket-creation-AF_INET6-failes-initialize.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0014-If-during-socket-creation-AF_INET6-failes-initialize.patch
new file mode 100644
index 000000000..4bb1ed21c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0014-If-during-socket-creation-AF_INET6-failes-initialize.patch
@@ -0,0 +1,27 @@ 
+From 1890bde5c051d932d1b2940e815d0c82964c474c Mon Sep 17 00:00:00 2001
+From: Gleb Smirnoff <glebius@FreeBSD.org>
+Date: Tue, 2 Oct 2018 18:57:43 -0700
+Subject: [PATCH] If during socket creation AF_INET6 failes initialize sockaddr
+ as AF_INET. Otherwise any bind(2) would fail due to sockaddr address family
+ not matching socket address family.
+
+---
+ src/net/listen.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/net/listen.cc b/src/net/listen.cc
+index da1c2e84..d424e94c 100644
+--- a/src/net/listen.cc
++++ b/src/net/listen.cc
+@@ -75,7 +75,10 @@ Listen::open(uint16_t first, uint16_t last, int backlog, const rak::socket_addre
+ 
+   // TODO: Temporary until we refactor:
+   if (bindAddress->family() == 0) {
+-    sa.sa_inet6()->clear();
++    if (m_ipv6_socket)
++      sa.sa_inet6()->clear();
++    else
++      sa.sa_inet()->clear();
+   } else {
+     sa.copy(*bindAddress, bindAddress->length());
+   }
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0015-Fixes-https-github.com-rakshasa-rtorrent-issues-731.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0015-Fixes-https-github.com-rakshasa-rtorrent-issues-731.patch
new file mode 100644
index 000000000..a33a0103b
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0015-Fixes-https-github.com-rakshasa-rtorrent-issues-731.patch
@@ -0,0 +1,29 @@ 
+From cbd946b6cad8c93b3d39ab4f338b3640f684cbfc Mon Sep 17 00:00:00 2001
+From: Adam Fontenot <adam.m.fontenot@gmail.com>
+Date: Sat, 7 Jul 2018 16:52:07 -0700
+Subject: [PATCH] Fixes https://github.com/rakshasa/rtorrent/issues/731
+
+---
+ src/tracker/tracker_http.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index eefe5a17..1bf94107 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -145,13 +145,13 @@ TrackerHttp::send_state(int state) {
+   if (!localAddress->is_address_any())
+     s << "&ip=" << localAddress->address_str();
+   
+-  if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet6) {
++  if (localAddress->is_address_any() && localAddress->family() == rak::socket_address::pf_inet) {
+     rak::socket_address local_v6;
+     if (get_local_address(rak::socket_address::af_inet6, &local_v6))
+       s << "&ipv6=" << rak::copy_escape_html(local_v6.address_str());
+   }
+ 
+-  if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet) {
++  if (localAddress->is_address_any() && localAddress->family() == rak::socket_address::pf_inet6) {
+     rak::socket_address local_v4;
+     if (get_local_address(rak::socket_address::af_inet, &local_v4))
+       s << "&ipv4=" << local_v4.address_str();
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0016-Fix-honoring-throttle.min_peers-settings-in-rtorrent.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0016-Fix-honoring-throttle.min_peers-settings-in-rtorrent.patch
new file mode 100644
index 000000000..6ef5f1ad4
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0016-Fix-honoring-throttle.min_peers-settings-in-rtorrent.patch
@@ -0,0 +1,40 @@ 
+From d49316117401cff4045b1d1194cec60909e45555 Mon Sep 17 00:00:00 2001
+From: chros <chros@chrosGX620>
+Date: Sun, 13 May 2018 11:34:33 +0100
+Subject: [PATCH] Fix honoring throttle.min_peers* settings in rtorrent (See
+ #13)
+
+---
+ src/download/download_main.cc | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+diff --git a/src/download/download_main.cc b/src/download/download_main.cc
+index 48222c38..efe91d66 100644
+--- a/src/download/download_main.cc
++++ b/src/download/download_main.cc
+@@ -355,19 +355,14 @@ DownloadMain::receive_tracker_success() {
+ 
+ void
+ DownloadMain::receive_tracker_request() {
+-  bool should_stop = false;
+-  bool should_start = false;
++  if (info()->is_pex_enabled() && info()->size_pex() > 0
++      || connection_list()->size() + peer_list()->available_list()->size() / 2 >= connection_list()->min_size()) {
+ 
+-  if (info()->is_pex_enabled() && info()->size_pex() > 0)
+-    should_stop = true;
+-
+-  if (connection_list()->size() + peer_list()->available_list()->size() / 2 < connection_list()->min_size())
+-    should_start = true;
+-
+-  if (should_stop)
+     m_tracker_controller->stop_requesting();
+-  else if (should_start)
+-    m_tracker_controller->start_requesting();
++    return;
++  }
++
++  m_tracker_controller->start_requesting();
+ }
+ 
+ struct SocketAddressCompact_less {
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0017-increase-piece-length-max.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0017-increase-piece-length-max.patch
new file mode 100644
index 000000000..7108507a1
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0017-increase-piece-length-max.patch
@@ -0,0 +1,22 @@ 
+From 9fd2f35f86397b9259e0c9b7c54444c0ec3c8965 Mon Sep 17 00:00:00 2001
+From: adam <adam@shinka.sh>
+Date: Mon, 26 Feb 2018 16:04:34 +0200
+Subject: [PATCH] increase piece length max
+
+---
+ src/download/download_constructor.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/download/download_constructor.cc b/src/download/download_constructor.cc
+index 1bb261bd..67ef4276 100644
+--- a/src/download/download_constructor.cc
++++ b/src/download/download_constructor.cc
+@@ -157,7 +157,7 @@ DownloadConstructor::parse_info(const Object& b) {
+   } else {
+     chunkSize = b.get_key_value("piece length");
+ 
+-    if (chunkSize <= (1 << 10) || chunkSize > (128 << 20))
++    if (chunkSize <= (1 << 10) || chunkSize > (128 << 22))
+       throw input_error("Torrent has an invalid \"piece length\".");
+   }
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0018-Set-max-piece-size-512mb.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0018-Set-max-piece-size-512mb.patch
new file mode 100644
index 000000000..f864d23c3
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0018-Set-max-piece-size-512mb.patch
@@ -0,0 +1,22 @@ 
+From b263b347f14b9d0ca54d04ca92367a98d791dc17 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Sun, 9 Jun 2019 14:53:32 +0900
+Subject: [PATCH] Set max piece size 512mb.
+
+---
+ src/download/download_constructor.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/download/download_constructor.cc b/src/download/download_constructor.cc
+index 67ef4276..1bf362fa 100644
+--- a/src/download/download_constructor.cc
++++ b/src/download/download_constructor.cc
+@@ -157,7 +157,7 @@ DownloadConstructor::parse_info(const Object& b) {
+   } else {
+     chunkSize = b.get_key_value("piece length");
+ 
+-    if (chunkSize <= (1 << 10) || chunkSize > (128 << 22))
++    if (chunkSize <= (1 << 10) || chunkSize > (512 << 20))
+       throw input_error("Torrent has an invalid \"piece length\".");
+   }
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0019-Fixed-compiler-warning.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0019-Fixed-compiler-warning.patch
new file mode 100644
index 000000000..0a06a2688
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0019-Fixed-compiler-warning.patch
@@ -0,0 +1,22 @@ 
+From cdfb4381bedb278dabb8ca75c10858d16b895355 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Sun, 9 Jun 2019 14:55:44 +0900
+Subject: [PATCH] Fixed compiler warning.
+
+---
+ src/download/download_main.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/download/download_main.cc b/src/download/download_main.cc
+index efe91d66..9a3f9df2 100644
+--- a/src/download/download_main.cc
++++ b/src/download/download_main.cc
+@@ -355,7 +355,7 @@ DownloadMain::receive_tracker_success() {
+ 
+ void
+ DownloadMain::receive_tracker_request() {
+-  if (info()->is_pex_enabled() && info()->size_pex() > 0
++  if ((info()->is_pex_enabled() && info()->size_pex()) > 0
+       || connection_list()->size() + peer_list()->available_list()->size() / 2 >= connection_list()->min_size()) {
+ 
+     m_tracker_controller->stop_requesting();
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0020-Added-_GNU_SOURCE-to-fallocate-test.-neheb.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0020-Added-_GNU_SOURCE-to-fallocate-test.-neheb.patch
new file mode 100644
index 000000000..0f183816c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0020-Added-_GNU_SOURCE-to-fallocate-test.-neheb.patch
@@ -0,0 +1,74 @@ 
+From 8934703edb5982661483eb8a29d76e6a726b5fe2 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Mon, 8 Jul 2019 19:37:06 +0200
+Subject: [PATCH] Added _GNU_SOURCE to fallocate test. (neheb)
+
+---
+ scripts/checks.m4       | 10 ++++++----
+ src/data/socket_file.cc |  1 +
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/scripts/checks.m4 b/scripts/checks.m4
+index c9333561..83be8461 100644
+--- a/scripts/checks.m4
++++ b/scripts/checks.m4
+@@ -88,7 +88,6 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
+     [
+       AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
+       AC_MSG_RESULT(yes)
+-      TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ], [
+       AC_MSG_RESULT(no)
+     ])
+@@ -97,7 +96,7 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
+ AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
+   AC_MSG_CHECKING(whether kqueue supports pipes and ptys)
+ 
+-  AC_RUN_IFELSE([AC_LANG_SOURCE([
++  AC_LINK_IFELSE([AC_LANG_SOURCE([
+       #include <fcntl.h>
+       #include <stdlib.h>
+       #include <unistd.h>
+@@ -138,6 +137,7 @@ AC_DEFUN([TORRENT_WITH_KQUEUE], [
+     [
+         if test "$withval" = "yes"; then
+           TORRENT_CHECK_KQUEUE
++          TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+         fi
+     ])
+ ])
+@@ -149,9 +149,11 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_KQUEUE
++        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+       fi
+     ], [
+         TORRENT_CHECK_KQUEUE
++        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ])
+ ])
+ 
+@@ -172,8 +174,8 @@ AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
+ AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
+   AC_MSG_CHECKING(for fallocate)
+ 
+-  AC_TRY_LINK([#include <fcntl.h>
+-               #include <linux/falloc.h>
++  AC_TRY_LINK([#define _GNU_SOURCE
++               #include <fcntl.h>
+               ],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
+               ],
+     [
+diff --git a/src/data/socket_file.cc b/src/data/socket_file.cc
+index 4b4519ed..b359ef8e 100644
+--- a/src/data/socket_file.cc
++++ b/src/data/socket_file.cc
+@@ -48,6 +48,7 @@
+ #include <sys/types.h>
+ 
+ #ifdef HAVE_FALLOCATE
++#define _GNU_SOURCE
+ #include <linux/falloc.h>
+ #endif
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0021-Fixed-diffie-hellman-implementation.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0021-Fixed-diffie-hellman-implementation.patch
new file mode 100644
index 000000000..ad9e45758
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0021-Fixed-diffie-hellman-implementation.patch
@@ -0,0 +1,293 @@ 
+From 856d42e2ca3c9810bf84a8bce219000e822540fa Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Fri, 12 Jul 2019 00:29:35 +0200
+Subject: [PATCH] Fixed diffie hellman implementation.
+
+---
+ src/utils/diffie_hellman.cc | 137 ++++++++++++------------------------
+ src/utils/diffie_hellman.h  |  67 ++++--------------
+ 2 files changed, 59 insertions(+), 145 deletions(-)
+
+diff --git a/src/utils/diffie_hellman.cc b/src/utils/diffie_hellman.cc
+index 7ec13165..d53a857b 100644
+--- a/src/utils/diffie_hellman.cc
++++ b/src/utils/diffie_hellman.cc
+@@ -1,118 +1,79 @@
+-// 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 "diffie_hellman.h"
++
++#include "torrent/exceptions.h"
++
+ #include <cstring>
+-#include <string>
+ 
+ #ifdef USE_OPENSSL
++#include <openssl/dh.h>
+ #include <openssl/bn.h>
+ #endif
+ 
+-#include "diffie_hellman.h"
+-#include "torrent/exceptions.h"
+-
+ namespace torrent {
+ 
+-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+-DiffieHellman::DiffieHellman(const unsigned char *prime, int primeLength,
+-                             const unsigned char *generator, int generatorLength) :
+-  m_secret(NULL), m_size(0) {
+-
+ #ifdef USE_OPENSSL
+ 
+-  m_dh = DH_new();
+-
+-#ifdef USE_OPENSSL_1_1
+-  BIGNUM * const dh_p = BN_bin2bn(prime, primeLength, NULL);
+-  BIGNUM * const dh_g = BN_bin2bn(generator, generatorLength, NULL);
++static void      dh_free(void* dh) { DH_free(reinterpret_cast<DH*>(dh)); }
++static DiffieHellman::dh_ptr dh_new() { return DiffieHellman::dh_ptr(reinterpret_cast<void*>(DH_new()), &dh_free); }
++static DH*       dh_get(DiffieHellman::dh_ptr& dh) { return reinterpret_cast<DH*>(dh.get()); }
+ 
+-  if (dh_p == NULL || dh_g == NULL ||
+-      !DH_set0_pqg(m_dh, dh_p, NULL, dh_g))
+-	  throw internal_error("Could not generate Diffie-Hellman parameters");
++static bool
++dh_set_pg(DiffieHellman::dh_ptr& dh, BIGNUM* dh_p, BIGNUM* dh_g) {
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++  return DH_set0_pqg(reinterpret_cast<DH*>(dh.get()), dh_p, nullptr, dh_g);
+ #else
+-  m_dh->p = BN_bin2bn(prime, primeLength, NULL);
+-  m_dh->g = BN_bin2bn(generator, generatorLength, NULL);
++  reinterpret_cast<DH*>(dh.get())->p = dh_p;
++  reinterpret_cast<DH*>(dh.get())->g = dh_g;
++  return true;
+ #endif
++}
+ 
+-  DH_generate_key(m_dh);
+-
++static const BIGNUM* dh_get_pub_key(const DiffieHellman::dh_ptr& dh) {
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++  const BIGNUM *pub_key;
++  DH_get0_key(reinterpret_cast<DH*>(dh.get()), &pub_key, nullptr);
++  return pub_key;
+ #else
+-  throw internal_error("Compiled without encryption support.");
++  return dh != nullptr ? reinterpret_cast<DH*>(dh.get())->pub_key : nullptr;
+ #endif
+-};
++}
+ 
+-DiffieHellman::~DiffieHellman() {
+-  delete [] m_secret;
+-#ifdef USE_OPENSSL
+-  DH_free(m_dh);
++#else
++static DiffieHellman::dh_ptr dh_new() { throw internal_error("Compiled without encryption support."); }
++static void  dh_free(void* dh) {}
++static void* dh_get_pub_key(const DiffieHellman::dh_ptr& dh) { return nullptr; }
+ #endif
+-};
+ 
+-bool
+-DiffieHellman::is_valid() const {
+-#ifdef USE_OPENSSL
+-  if (m_dh == NULL)
+-    return false;
++#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
++DiffieHellman::DiffieHellman(const unsigned char *prime, int primeLength,
++                             const unsigned char *generator, int generatorLength) :
++  m_dh(dh_new()), m_size(0) {
+ 
+-#ifdef USE_OPENSSL_1_1
+-  const BIGNUM *pub_key;
++#ifdef USE_OPENSSL
++  BIGNUM* dh_p = BN_bin2bn(prime, primeLength, nullptr);
++  BIGNUM* dh_g = BN_bin2bn(generator, generatorLength, nullptr);
+ 
+-  DH_get0_key(m_dh, &pub_key, NULL);
++  if (dh_p == nullptr || dh_g == nullptr || !dh_set_pg(m_dh, dh_p, dh_g))
++    throw internal_error("Could not generate Diffie-Hellman parameters");
+ 
+-  return pub_key != NULL;
+-#else
+-  return m_dh != NULL && m_dh->pub_key != NULL;
++  DH_generate_key(dh_get(m_dh));
+ #endif
++};
+ 
+-#else
+-  return false;
+-#endif
++bool
++DiffieHellman::is_valid() const {
++  return dh_get_pub_key(m_dh) != nullptr;
+ }
+ 
+ bool
+ DiffieHellman::compute_secret(const unsigned char *pubkey, unsigned int length) {
+ #ifdef USE_OPENSSL
+-  BIGNUM* k = BN_bin2bn(pubkey, length, NULL);
++  BIGNUM* k = BN_bin2bn(pubkey, length, nullptr);
+ 
+-  delete [] m_secret;
+-  m_secret = new char[DH_size(m_dh)];
+-
+-  m_size = DH_compute_key((unsigned char*)m_secret, k, m_dh);
++  m_secret.reset(new char[DH_size(dh_get(m_dh))]);
++  m_size = DH_compute_key(reinterpret_cast<unsigned char*>(m_secret.get()), k, dh_get(m_dh));
+   
+   BN_free(k);
+ 
+@@ -124,16 +85,10 @@ DiffieHellman::compute_secret(const unsigned char *pubkey, unsigned int length)
+ 
+ void
+ DiffieHellman::store_pub_key(unsigned char* dest, unsigned int length) {
+-#ifdef USE_OPENSSL
+   std::memset(dest, 0, length);
+ 
+-  const BIGNUM *pub_key;
+-
+-#ifdef USE_OPENSSL_1_1
+-  DH_get0_key(m_dh, &pub_key, NULL);
+-#else
+-  pub_key = m_dh->pub_key;
+-#endif
++#ifdef USE_OPENSSL
++  const BIGNUM *pub_key = dh_get_pub_key(m_dh);
+ 
+   if ((int)length >= BN_num_bytes(pub_key))
+     BN_bn2bin(pub_key, dest + length - BN_num_bytes(pub_key));
+diff --git a/src/utils/diffie_hellman.h b/src/utils/diffie_hellman.h
+index 432542be..2cec5bee 100644
+--- a/src/utils/diffie_hellman.h
++++ b/src/utils/diffie_hellman.h
+@@ -1,79 +1,38 @@
+-// 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_DIFFIE_HELLMAN_H
+ #define LIBTORRENT_DIFFIE_HELLMAN_H
+ 
+ #include "config.h"
+ 
++#include <memory>
+ #include <string>
+ 
+-#ifdef USE_OPENSSL
+-#include <openssl/dh.h>
+-#endif
+-
+ namespace torrent {
+ 
+ class DiffieHellman {
+ public:
++  typedef std::unique_ptr<char[]> secret_ptr;
++  typedef std::unique_ptr<void, void (*)(void*)> dh_ptr;
++
+   DiffieHellman(const unsigned char prime[], int primeLength,
+                 const unsigned char generator[], int generatorLength);
+-  ~DiffieHellman();
+ 
+-  bool                compute_secret(const unsigned char pubkey[], unsigned int length);
+-  void                store_pub_key(unsigned char* dest, unsigned int length);
++  bool         is_valid() const;
+ 
+-  bool                is_valid() const;
++  bool         compute_secret(const unsigned char pubkey[], unsigned int length);
++  void         store_pub_key(unsigned char* dest, unsigned int length);
+ 
+-  unsigned int        size() const         { return m_size; }
++  unsigned int size() const         { return m_size; }
+ 
+-  const char*         c_str() const        { return m_secret; }
+-  std::string         secret_str() const   { return std::string(m_secret, m_size); }
++  const char*  c_str() const        { return m_secret.get(); }
++  std::string  secret_str() const   { return std::string(m_secret.get(), m_size); }
+ 
+ private:
+   DiffieHellman(const DiffieHellman& dh);
+   DiffieHellman& operator = (const DiffieHellman& dh);
+ 
+-#ifdef USE_OPENSSL
+-  DH*                 m_dh;
+-#else
+-  void*               m_void;
+-#endif
+-  char*               m_secret;
+-  unsigned int        m_size;
++  dh_ptr       m_dh;
++  secret_ptr   m_secret;
++  int          m_size;
+ };
+ 
+ };
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0022-Increased-max-timeout-for-tracker-requests.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0022-Increased-max-timeout-for-tracker-requests.patch
new file mode 100644
index 000000000..66f43f0ce
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0022-Increased-max-timeout-for-tracker-requests.patch
@@ -0,0 +1,64 @@ 
+From 660bbc17e32c518c2727607ee5b73039c7109207 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Sat, 13 Jul 2019 00:07:43 +0200
+Subject: [PATCH] Increased max timeout for tracker requests.
+
+---
+ src/torrent/tracker.h | 40 ++--------------------------------------
+ 1 file changed, 2 insertions(+), 38 deletions(-)
+
+diff --git a/src/torrent/tracker.h b/src/torrent/tracker.h
+index 2b00ad47..a528ef6a 100644
+--- a/src/torrent/tracker.h
++++ b/src/torrent/tracker.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_TRACKER_H
+ #define LIBTORRENT_TRACKER_H
+ 
+@@ -148,8 +112,8 @@ protected:
+ 
+   void                set_group(uint32_t v)                 { m_group = v; }
+ 
+-  void                set_normal_interval(int v)            { m_normal_interval = std::min(std::max(600, v), 3600); }
+-  void                set_min_interval(int v)               { m_min_interval = std::min(std::max(300, v), 1800); }
++  void                set_normal_interval(int v)            { m_normal_interval = std::min(std::max(600, v), 8 * 3600); }
++  void                set_min_interval(int v)               { m_min_interval = std::min(std::max(300, v), 4 * 3600); }
+ 
+   int                 m_flags;
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0023-Close-log-files-when-reusing-a-name.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0023-Close-log-files-when-reusing-a-name.patch
new file mode 100644
index 000000000..885b1828d
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0023-Close-log-files-when-reusing-a-name.patch
@@ -0,0 +1,123 @@ 
+From efc75948253c1a8db482daabf45d9eabaaf4b099 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Wed, 17 Jul 2019 19:41:04 +0200
+Subject: [PATCH] Close log files when reusing a name.
+
+---
+ src/torrent/utils/log.cc             | 20 ++++++++++++++++----
+ src/torrent/utils/log.h              |  7 +++++++
+ test/torrent/tracker_timeout_test.cc |  8 ++++----
+ test/torrent/utils/log_test.cc       | 12 ++++++------
+ 4 files changed, 33 insertions(+), 14 deletions(-)
+
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index 58b563a6..5169a730 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -294,12 +294,16 @@ log_open_output(const char* name, log_slot slot) {
+     throw input_error("Cannot open more than 64 log output handlers.");
+   }
+   
+-  if (log_find_output_name(name) != log_outputs.end()) {
+-    pthread_mutex_unlock(&log_mutex);
+-    throw input_error("Log name already used.");
++  log_output_list::iterator itr = log_find_output_name(name);
++
++  if (itr == log_outputs.end()) {
++    log_outputs.push_back(std::make_pair(name, slot));
++  } else {
++    // by replacing the "write" slot binding, the old file gets closed
++    // (handles are shared pointers)
++    itr->second = slot;
+   }
+ 
+-  log_outputs.push_back(std::make_pair(name, slot));
+   log_rebuild_cache();
+ 
+   pthread_mutex_unlock(&log_mutex);
+@@ -307,6 +311,14 @@ log_open_output(const char* name, log_slot slot) {
+ 
+ void
+ log_close_output(const char* name) {
++  pthread_mutex_lock(&log_mutex);
++
++  log_output_list::iterator itr = log_find_output_name(name);
++
++  if (itr != log_outputs.end())
++    log_outputs.erase(itr);
++
++  pthread_mutex_unlock(&log_mutex);
+ }
+ 
+ void
+diff --git a/src/torrent/utils/log.h b/src/torrent/utils/log.h
+index a053d6ec..430bda5e 100644
+--- a/src/torrent/utils/log.h
++++ b/src/torrent/utils/log.h
+@@ -229,6 +229,7 @@ void log_cleanup() LIBTORRENT_EXPORT;
+ 
+ void log_open_output(const char* name, log_slot slot) LIBTORRENT_EXPORT;
+ void log_close_output(const char* name) LIBTORRENT_EXPORT;
++void log_close_output_str(const std::string name) LIBTORRENT_EXPORT;
+ 
+ void log_add_group_output(int group, const char* name) LIBTORRENT_EXPORT;
+ void log_remove_group_output(int group, const char* name) LIBTORRENT_EXPORT;
+@@ -240,6 +241,12 @@ void        log_open_file_output(const char* name, const char* filename) LIBTORR
+ void        log_open_gz_file_output(const char* name, const char* filename) LIBTORRENT_EXPORT;
+ log_buffer* log_open_log_buffer(const char* name) LIBTORRENT_EXPORT;
+ 
++//
++// Implementation:
++//
++
++inline void log_close_output_str(const std::string name) { log_close_output(name.c_str()); }
++
+ }
+ 
+ #endif
+diff --git a/test/torrent/tracker_timeout_test.cc b/test/torrent/tracker_timeout_test.cc
+index 081b9301..cd060006 100644
+--- a/test/torrent/tracker_timeout_test.cc
++++ b/test/torrent/tracker_timeout_test.cc
+@@ -29,13 +29,13 @@ tracker_timeout_test::test_set_timeout() {
+ 
+   tracker.set_new_normal_interval(100);
+   CPPUNIT_ASSERT(tracker.normal_interval() == 600);
+-  tracker.set_new_normal_interval(4000);
+-  CPPUNIT_ASSERT(tracker.normal_interval() == 3600);
++  tracker.set_new_normal_interval(8 * 4000);
++  CPPUNIT_ASSERT(tracker.normal_interval() == 8 * 3600);
+ 
+   tracker.set_new_min_interval(100);
+   CPPUNIT_ASSERT(tracker.min_interval() == 300);
+-  tracker.set_new_min_interval(4000);
+-  CPPUNIT_ASSERT(tracker.min_interval() == 1800);
++  tracker.set_new_min_interval(4 * 4000);
++  CPPUNIT_ASSERT(tracker.min_interval() == 4 * 3600);
+ }
+ 
+ void
+diff --git a/test/torrent/utils/log_test.cc b/test/torrent/utils/log_test.cc
+index 9b99c245..24c22b59 100644
+--- a/test/torrent/utils/log_test.cc
++++ b/test/torrent/utils/log_test.cc
+@@ -75,13 +75,13 @@ utils_log_test::test_output_open() {
+   // Test inserting duplicate names, should catch.
+   // CPPUNIT_ASSERT_THROW(torrent::log_open_output("test_output_1", torrent::log_slot());, torrent::input_error);
+ 
+-  try {
+-    torrent::log_open_output("test_output_1", torrent::log_slot());
+-  } catch (torrent::input_error& e) {
+-    return;
+-  }
++  // try {
++  //   torrent::log_open_output("test_output_1", torrent::log_slot());
++  // } catch (torrent::input_error& e) {
++  //   return;
++  // }
+ 
+-  CPPUNIT_ASSERT(false);
++  // CPPUNIT_ASSERT(false);
+ 
+   // Test more than 64 entries.
+ }
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0024-Bumped-to-version-0.13.8.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0024-Bumped-to-version-0.13.8.patch
new file mode 100644
index 000000000..ffe6b3f22
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0024-Bumped-to-version-0.13.8.patch
@@ -0,0 +1,30 @@ 
+From 7faa9c58ce098bbdeff83b6add72f3075b47881d Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Fri, 19 Jul 2019 13:38:12 +0200
+Subject: [PATCH] Bumped to version 0.13.8.
+
+---
+ configure.ac | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index b885714d..4ed08124 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,12 +1,12 @@
+-AC_INIT(libtorrent, 0.13.7, sundell.software@gmail.com)
++AC_INIT(libtorrent, 0.13.8, sundell.software@gmail.com)
+ 
+ LT_INIT([disable-static])
+ 
+ dnl Find a better way to do this
+-AC_DEFINE(PEER_NAME, "-lt0D70-", Identifier that is part of the default peer id)
+-AC_DEFINE(PEER_VERSION, "lt\x0D\x70", 4 byte client and version identifier for DHT)
++AC_DEFINE(PEER_NAME, "-lt0D80-", Identifier that is part of the default peer id)
++AC_DEFINE(PEER_VERSION, "lt\x0D\x80", 4 byte client and version identifier for DHT)
+ 
+-LIBTORRENT_CURRENT=20
++LIBTORRENT_CURRENT=21
+ LIBTORRENT_REVISION=0
+ LIBTORRENT_AGE=0
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0025-Allow-logs-to-be-appended-rather-than-overwritten.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0025-Allow-logs-to-be-appended-rather-than-overwritten.patch
new file mode 100644
index 000000000..c8884d856
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0025-Allow-logs-to-be-appended-rather-than-overwritten.patch
@@ -0,0 +1,109 @@ 
+From 7667094274879fe158e718bf2765d35f82d924bd Mon Sep 17 00:00:00 2001
+From: nicholi <nschell@gmail.com>
+Date: Tue, 23 Jul 2019 23:59:16 -0700
+Subject: [PATCH] Allow logs to be appended rather than overwritten.
+
+---
+ src/torrent/utils/log.cc       | 13 +++++++++++++
+ src/torrent/utils/log.h        |  1 +
+ test/torrent/utils/log_test.cc | 35 ++++++++++++++++++++++++++++++++++
+ test/torrent/utils/log_test.h  |  2 ++
+ 4 files changed, 51 insertions(+)
+
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index 5169a730..a900c109 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -428,6 +428,19 @@ log_open_file_output(const char* name, const char* filename) {
+                                   std::placeholders::_3));
+ }
+ 
++void
++log_open_file_output_append(const char* name, const char* filename) {
++  std::shared_ptr<std::ofstream> outfile(new std::ofstream(filename, std::ofstream::out | std::ofstream::app));
++
++  if (!outfile->good())
++    throw input_error("Could not open log file '" + std::string(filename) + "'.");
++
++  log_open_output(name, std::bind(&log_file_write, outfile,
++                                  std::placeholders::_1,
++                                  std::placeholders::_2,
++                                  std::placeholders::_3));
++}
++
+ void
+ log_open_gz_file_output(const char* name, const char* filename) {
+   std::shared_ptr<log_gz_output> outfile(new log_gz_output(filename));
+diff --git a/src/torrent/utils/log.h b/src/torrent/utils/log.h
+index 430bda5e..531c8565 100644
+--- a/src/torrent/utils/log.h
++++ b/src/torrent/utils/log.h
+@@ -238,6 +238,7 @@ void log_add_child(int group, int child) LIBTORRENT_EXPORT;
+ void log_remove_child(int group, int child) LIBTORRENT_EXPORT;
+ 
+ void        log_open_file_output(const char* name, const char* filename) LIBTORRENT_EXPORT;
++void        log_open_file_output_append(const char* name, const char* filename) LIBTORRENT_EXPORT;
+ void        log_open_gz_file_output(const char* name, const char* filename) LIBTORRENT_EXPORT;
+ log_buffer* log_open_log_buffer(const char* name) LIBTORRENT_EXPORT;
+ 
+diff --git a/test/torrent/utils/log_test.cc b/test/torrent/utils/log_test.cc
+index 24c22b59..aa13fff8 100644
+--- a/test/torrent/utils/log_test.cc
++++ b/test/torrent/utils/log_test.cc
+@@ -155,3 +155,38 @@ utils_log_test::test_file_output() {
+ 
+   CPPUNIT_ASSERT_MESSAGE(buffer, std::string(buffer).find("test_file") != std::string::npos);
+ }
++
++void
++utils_log_test::test_file_output_append() {
++  std::string filename = "utils_log_test.XXXXXX";
++
++  mktemp(&*filename.begin());
++
++  torrent::log_open_file_output_append("test_file", filename.c_str());
++  torrent::log_add_group_output(GROUP_PARENT_1, "test_file");
++
++  lt_log_print(GROUP_PARENT_1, "test_line_1");
++
++  torrent::log_cleanup(); // To ensure we flush the buffers.
++
++  // re-open and write 2nd line
++  torrent::log_open_file_output_append("test_file", filename.c_str());
++  torrent::log_add_group_output(GROUP_PARENT_1, "test_file");
++
++  lt_log_print(GROUP_PARENT_1, "test_line_2");
++
++  torrent::log_cleanup(); // To ensure we flush the buffers.
++
++  std::ifstream temp_file(filename.c_str());
++
++  CPPUNIT_ASSERT(temp_file.good());
++
++  char buffer_line1[256];
++  temp_file.getline(buffer_line1, 256);
++
++  char buffer_line2[256];
++  temp_file.getline(buffer_line2, 256);
++
++  CPPUNIT_ASSERT_MESSAGE(buffer_line1, std::string(buffer_line1).find("test_line_1") != std::string::npos);
++  CPPUNIT_ASSERT_MESSAGE(buffer_line2, std::string(buffer_line2).find("test_line_2") != std::string::npos);
++}
+diff --git a/test/torrent/utils/log_test.h b/test/torrent/utils/log_test.h
+index 3a66cc24..d4cb3bc6 100644
+--- a/test/torrent/utils/log_test.h
++++ b/test/torrent/utils/log_test.h
+@@ -10,6 +10,7 @@ class utils_log_test : public CppUnit::TestFixture {
+   CPPUNIT_TEST(test_print);
+   CPPUNIT_TEST(test_children);
+   CPPUNIT_TEST(test_file_output);
++  CPPUNIT_TEST(test_file_output_append);
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+@@ -22,4 +23,5 @@ public:
+   void test_print();
+   void test_children();
+   void test_file_output();
++  void test_file_output_append();
+ };
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0026-Removed-log-append-function.-Added-append-parameter-.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0026-Removed-log-append-function.-Added-append-parameter-.patch
new file mode 100644
index 000000000..9859f954c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0026-Removed-log-append-function.-Added-append-parameter-.patch
@@ -0,0 +1,101 @@ 
+From df54913c34c8b584d6d2072a65ad1590766780c5 Mon Sep 17 00:00:00 2001
+From: nicholi <nschell@gmail.com>
+Date: Fri, 26 Jul 2019 00:50:52 -0700
+Subject: [PATCH] Removed log append function. Added append parameter with
+ default value (false) to log_open_file functions.
+
+---
+ src/torrent/utils/log.cc       | 26 ++++++++------------------
+ src/torrent/utils/log.h        |  5 ++---
+ test/torrent/utils/log_test.cc |  4 ++--
+ 3 files changed, 12 insertions(+), 23 deletions(-)
+
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index a900c109..6c605474 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -73,7 +73,7 @@ struct log_cache_entry {
+ };
+ 
+ struct log_gz_output {
+-  log_gz_output(const char* filename) { gz_file = gzopen(filename, "w"); }
++  log_gz_output(const char* filename, bool append) { gz_file = gzopen(filename, append ? "a" : "w"); }
+   ~log_gz_output() { if (gz_file != NULL) gzclose(gz_file); }
+ 
+   bool is_valid() { return gz_file != Z_NULL; }
+@@ -416,8 +416,11 @@ log_gz_file_write(std::shared_ptr<log_gz_output>& outfile, const char* data, siz
+ }
+ 
+ void
+-log_open_file_output(const char* name, const char* filename) {
+-  std::shared_ptr<std::ofstream> outfile(new std::ofstream(filename));
++log_open_file_output(const char* name, const char* filename, bool append) {
++  std::ios_base::openmode mode = std::ofstream::out;
++  if (append)
++    mode |= std::ofstream::app;
++  std::shared_ptr<std::ofstream> outfile(new std::ofstream(filename, mode));
+ 
+   if (!outfile->good())
+     throw input_error("Could not open log file '" + std::string(filename) + "'.");
+@@ -429,21 +432,8 @@ log_open_file_output(const char* name, const char* filename) {
+ }
+ 
+ void
+-log_open_file_output_append(const char* name, const char* filename) {
+-  std::shared_ptr<std::ofstream> outfile(new std::ofstream(filename, std::ofstream::out | std::ofstream::app));
+-
+-  if (!outfile->good())
+-    throw input_error("Could not open log file '" + std::string(filename) + "'.");
+-
+-  log_open_output(name, std::bind(&log_file_write, outfile,
+-                                  std::placeholders::_1,
+-                                  std::placeholders::_2,
+-                                  std::placeholders::_3));
+-}
+-
+-void
+-log_open_gz_file_output(const char* name, const char* filename) {
+-  std::shared_ptr<log_gz_output> outfile(new log_gz_output(filename));
++log_open_gz_file_output(const char* name, const char* filename, bool append) {
++  std::shared_ptr<log_gz_output> outfile(new log_gz_output(filename, append));
+ 
+   if (!outfile->is_valid())
+     throw input_error("Could not open log gzip file '" + std::string(filename) + "'.");
+diff --git a/src/torrent/utils/log.h b/src/torrent/utils/log.h
+index 531c8565..0dfdc86b 100644
+--- a/src/torrent/utils/log.h
++++ b/src/torrent/utils/log.h
+@@ -237,9 +237,8 @@ void log_remove_group_output(int group, const char* name) LIBTORRENT_EXPORT;
+ void log_add_child(int group, int child) LIBTORRENT_EXPORT;
+ void log_remove_child(int group, int child) LIBTORRENT_EXPORT;
+ 
+-void        log_open_file_output(const char* name, const char* filename) LIBTORRENT_EXPORT;
+-void        log_open_file_output_append(const char* name, const char* filename) LIBTORRENT_EXPORT;
+-void        log_open_gz_file_output(const char* name, const char* filename) LIBTORRENT_EXPORT;
++void        log_open_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
++void        log_open_gz_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
+ log_buffer* log_open_log_buffer(const char* name) LIBTORRENT_EXPORT;
+ 
+ //
+diff --git a/test/torrent/utils/log_test.cc b/test/torrent/utils/log_test.cc
+index aa13fff8..9f975636 100644
+--- a/test/torrent/utils/log_test.cc
++++ b/test/torrent/utils/log_test.cc
+@@ -162,7 +162,7 @@ utils_log_test::test_file_output_append() {
+ 
+   mktemp(&*filename.begin());
+ 
+-  torrent::log_open_file_output_append("test_file", filename.c_str());
++  torrent::log_open_file_output("test_file", filename.c_str(), false);
+   torrent::log_add_group_output(GROUP_PARENT_1, "test_file");
+ 
+   lt_log_print(GROUP_PARENT_1, "test_line_1");
+@@ -170,7 +170,7 @@ utils_log_test::test_file_output_append() {
+   torrent::log_cleanup(); // To ensure we flush the buffers.
+ 
+   // re-open and write 2nd line
+-  torrent::log_open_file_output_append("test_file", filename.c_str());
++  torrent::log_open_file_output("test_file", filename.c_str(), true);
+   torrent::log_add_group_output(GROUP_PARENT_1, "test_file");
+ 
+   lt_log_print(GROUP_PARENT_1, "test_line_2");
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0027-Backport-changes-from-feature-bind.-200.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0027-Backport-changes-from-feature-bind.-200.patch
new file mode 100644
index 000000000..6b1578bde
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0027-Backport-changes-from-feature-bind.-200.patch
@@ -0,0 +1,7365 @@ 
+From b0f945e11d6afe43c917b58291c6fbcf5468a908 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Fri, 23 Aug 2019 23:23:48 +0900
+Subject: [PATCH] Backport changes from feature-bind. (#200)
+
+---
+ .dir-locals.el                                |   7 +
+ Makefile.am                                   |   1 +
+ configure.ac                                  |  40 +-
+ extra/corrupt_file.cc                         |   2 +-
+ rak/file_stat.h                               |   2 +-
+ rak/fs_stat.h                                 |   2 +-
+ rak/partial_queue.h                           |   2 +-
+ rak/path.h                                    |   2 +-
+ rak/priority_queue_default.h                  |   2 +-
+ rak/socket_address.h                          |  49 +-
+ rak/timer.h                                   |   2 +-
+ scripts/checks.m4                             |   4 +-
+ scripts/rak_cxx.m4                            |  47 --
+ scripts/ssl.m4                                |  38 ++
+ src/data/chunk_list.cc                        |   2 -
+ src/data/chunk_list.h                         |   2 +-
+ src/data/chunk_list_node.h                    |   2 +-
+ src/data/hash_check_queue.h                   |   2 +-
+ src/data/hash_queue.cc                        |   2 -
+ src/data/hash_queue.h                         |   2 +-
+ src/data/hash_queue_node.h                    |   4 +-
+ src/data/hash_torrent.cc                      |   2 -
+ src/data/hash_torrent.h                       |   4 +-
+ src/data/memory_chunk.h                       |   2 +-
+ src/data/socket_file.h                        |   2 +-
+ src/dht/dht_hash_map.h                        |  57 +-
+ src/download/chunk_selector.h                 |   2 +-
+ src/download/chunk_statistics.h               |   2 +-
+ src/download/delegator.cc                     |   2 +-
+ src/download/delegator.h                      |   2 +-
+ src/download/download_constructor.h           |   2 +-
+ src/globals.cc                                |  15 +-
+ src/globals.h                                 |  36 --
+ src/manager.cc                                |  36 --
+ src/net/Makefile.am                           |   2 +
+ src/net/data_buffer.h                         |   2 +-
+ src/net/listen.cc                             |  40 +-
+ src/net/listen.h                              |   4 +-
+ src/net/protocol_buffer.h                     |   2 +-
+ src/net/socket_base.h                         |   2 +-
+ src/net/socket_fd.cc                          |  10 +
+ src/net/socket_fd.h                           |   6 +
+ src/net/socket_listen.cc                      | 137 +++++
+ src/net/socket_listen.h                       |  46 ++
+ src/net/socket_set.h                          |   2 +-
+ src/net/throttle_node.h                       |   2 +-
+ src/protocol/handshake.cc                     |  13 +-
+ src/protocol/handshake_manager.cc             |  56 +-
+ src/protocol/handshake_manager.h              |  40 +-
+ src/protocol/peer_connection_base.cc          |   2 -
+ src/protocol/request_list.cc                  |  38 +-
+ src/torrent/Makefile.am                       |   1 +
+ src/torrent/common.h                          |   5 +-
+ src/torrent/connection_manager.h              |   2 +-
+ src/torrent/data/download_data.h              |   2 +-
+ src/torrent/data/file_list.cc                 |   2 -
+ src/torrent/data/transfer_list.h              |   3 +-
+ src/torrent/download.cc                       |   4 +-
+ src/torrent/download/choke_group.cc           |   2 +-
+ src/torrent/download/choke_group.h            |   2 +-
+ src/torrent/download/choke_queue.cc           |   3 +-
+ src/torrent/download/choke_queue.h            |   5 +-
+ src/torrent/download/group_entry.h            |   3 +-
+ src/torrent/download/resource_manager.cc      |   1 -
+ src/torrent/download/resource_manager.h       |   2 +-
+ src/torrent/download_info.h                   |   4 +-
+ src/torrent/error.cc                          |   6 +-
+ src/torrent/error.h                           |   7 +-
+ src/torrent/event.cc                          |  19 +
+ src/torrent/event.h                           |  82 ++-
+ src/torrent/http.h                            |   2 +-
+ src/torrent/net/Makefile.am                   |  18 +-
+ src/torrent/net/address_info.cc               |  43 ++
+ src/torrent/net/address_info.h                |  69 +++
+ src/torrent/net/fd.cc                         | 209 +++++++
+ src/torrent/net/fd.h                          |  63 ++
+ src/torrent/net/socket_address.cc             | 559 ++++++++++++++++++
+ src/torrent/net/socket_address.h              | 229 +++++++
+ src/torrent/net/socket_address_key.h          |   2 +-
+ src/torrent/net/socket_event.cc               |  29 +
+ src/torrent/net/socket_event.h                |  31 +
+ src/torrent/net/types.h                       |  33 ++
+ src/torrent/object.h                          |  21 +-
+ src/torrent/peer/client_list.cc               |   2 +-
+ src/torrent/peer/connection_list.h            |   3 +-
+ src/torrent/peer/peer_list.cc                 |   7 +-
+ src/torrent/poll.h                            |   3 +-
+ src/torrent/torrent.cc                        |  42 +-
+ src/torrent/torrent.h                         |  11 +-
+ src/torrent/tracker.h                         |   2 +-
+ src/torrent/tracker_controller.h              |   3 +-
+ src/torrent/tracker_list.h                    |   2 +-
+ src/torrent/utils/Makefile.am                 |   5 +-
+ src/torrent/utils/directory_events.h          |   3 +-
+ src/torrent/utils/log.cc                      |  66 +--
+ src/torrent/utils/log.h                       |  98 ++-
+ src/torrent/utils/log_buffer.cc               |  55 +-
+ src/torrent/utils/log_buffer.h                |  52 +-
+ src/torrent/utils/net.cc                      |  72 ---
+ src/torrent/utils/net.h                       |  56 --
+ src/torrent/utils/option_strings.cc           |  63 +-
+ src/torrent/utils/option_strings.h            |   7 +-
+ src/torrent/utils/random.cc                   |  29 +
+ src/torrent/utils/random.h                    |  15 +
+ src/torrent/utils/ranges.h                    |   1 -
+ src/torrent/utils/resume.cc                   |   2 -
+ src/torrent/utils/signal_bitfield.h           |   3 +-
+ src/torrent/utils/thread_base.h               |   3 +-
+ src/utils/instrumentation.cc                  |   2 -
+ src/utils/instrumentation.h                   |   3 +-
+ src/utils/queue_buckets.h                     |   4 +-
+ src/utils/sha_fast.h                          |   2 +-
+ test/Makefile.am                              |  29 +-
+ test/data/hash_check_queue_test.cc            |   2 +-
+ test/data/hash_queue_test.cc                  |   2 +-
+ test/helpers/expect_fd.h                      | 107 ++++
+ test/helpers/expect_utils.h                   |  13 +
+ test/helpers/mock_compare.h                   |  96 +++
+ test/helpers/mock_function.cc                 | 170 ++++++
+ test/helpers/mock_function.h                  | 133 +++++
+ test/helpers/network.h                        | 182 ++++++
+ test/helpers/progress_listener.cc             |  63 ++
+ test/helpers/progress_listener.h              |  47 ++
+ test/helpers/test_fixture.cc                  |  18 +
+ test/helpers/test_fixture.h                   |  14 +
+ test/helpers/utils.h                          |  60 ++
+ test/main.cc                                  |  82 ++-
+ test/net/test_socket_listen.cc                | 398 +++++++++++++
+ test/net/test_socket_listen.h                 |  44 ++
+ test/torrent/net/test_address_info.cc         |  62 ++
+ test/torrent/net/test_address_info.h          |  19 +
+ test/torrent/net/test_fd.cc                   |  24 +
+ test/torrent/net/test_fd.h                    |  12 +
+ test/torrent/net/test_socket_address.cc       | 383 ++++++++++++
+ test/torrent/net/test_socket_address.h        |  43 ++
+ test/torrent/net/test_socket_address_key.cc   |  87 ---
+ test/torrent/object_stream_test.cc            |   4 +-
+ test/torrent/tracker_controller_features.cc   |   2 +-
+ test/torrent/tracker_controller_requesting.cc |   2 +-
+ test/torrent/tracker_controller_test.cc       |   2 +-
+ test/torrent/tracker_list_features_test.cc    |   2 +-
+ test/torrent/utils/directory_events_test.cc   |   4 +-
+ test/torrent/utils/log_buffer_test.h          |  17 -
+ test/torrent/utils/log_test.cc                |   4 +-
+ test/torrent/utils/net_test.cc                |  32 -
+ test/torrent/utils/net_test.h                 |  15 -
+ test/torrent/utils/option_strings_test.cc     |   3 +-
+ test/torrent/utils/test_extents.cc            |   2 +-
+ ...{log_buffer_test.cc => test_log_buffer.cc} |  14 +-
+ test/torrent/utils/test_log_buffer.h          |  17 +
+ test/torrent/utils/test_uri_parser.cc         |   2 +-
+ test/torrent/utils/thread_base_test.cc        |   3 +-
+ 152 files changed, 3968 insertions(+), 1110 deletions(-)
+ create mode 100644 .dir-locals.el
+ create mode 100644 scripts/ssl.m4
+ create mode 100644 src/net/socket_listen.cc
+ create mode 100644 src/net/socket_listen.h
+ create mode 100644 src/torrent/event.cc
+ create mode 100644 src/torrent/net/address_info.cc
+ create mode 100644 src/torrent/net/address_info.h
+ create mode 100644 src/torrent/net/fd.cc
+ create mode 100644 src/torrent/net/fd.h
+ create mode 100644 src/torrent/net/socket_address.cc
+ create mode 100644 src/torrent/net/socket_address.h
+ create mode 100644 src/torrent/net/socket_event.cc
+ create mode 100644 src/torrent/net/socket_event.h
+ create mode 100644 src/torrent/net/types.h
+ delete mode 100644 src/torrent/utils/net.cc
+ delete mode 100644 src/torrent/utils/net.h
+ create mode 100644 src/torrent/utils/random.cc
+ create mode 100644 src/torrent/utils/random.h
+ create mode 100644 test/helpers/expect_fd.h
+ create mode 100644 test/helpers/expect_utils.h
+ create mode 100644 test/helpers/mock_compare.h
+ create mode 100644 test/helpers/mock_function.cc
+ create mode 100644 test/helpers/mock_function.h
+ create mode 100644 test/helpers/network.h
+ create mode 100644 test/helpers/progress_listener.cc
+ create mode 100644 test/helpers/progress_listener.h
+ create mode 100644 test/helpers/test_fixture.cc
+ create mode 100644 test/helpers/test_fixture.h
+ create mode 100644 test/helpers/utils.h
+ create mode 100644 test/net/test_socket_listen.cc
+ create mode 100644 test/net/test_socket_listen.h
+ create mode 100644 test/torrent/net/test_address_info.cc
+ create mode 100644 test/torrent/net/test_address_info.h
+ create mode 100644 test/torrent/net/test_fd.cc
+ create mode 100644 test/torrent/net/test_fd.h
+ create mode 100644 test/torrent/net/test_socket_address.cc
+ create mode 100644 test/torrent/net/test_socket_address.h
+ delete mode 100644 test/torrent/net/test_socket_address_key.cc
+ delete mode 100644 test/torrent/utils/log_buffer_test.h
+ delete mode 100644 test/torrent/utils/net_test.cc
+ delete mode 100644 test/torrent/utils/net_test.h
+ rename test/torrent/utils/{log_buffer_test.cc => test_log_buffer.cc} (86%)
+ create mode 100644 test/torrent/utils/test_log_buffer.h
+
+diff --git a/.dir-locals.el b/.dir-locals.el
+new file mode 100644
+index 00000000..af1189f2
+--- /dev/null
++++ b/.dir-locals.el
+@@ -0,0 +1,7 @@
++;;; Directory Local Variables
++;;; For more information see (info "(emacs) Directory Variables")
++
++((c++-mode
++  (flycheck-clang-language-standard . "c++11")
++  (flycheck-gcc-language-standard . "c++11")))
++
+diff --git a/Makefile.am b/Makefile.am
+index f175e634..9507b9ea 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -8,6 +8,7 @@ EXTRA_DIST= \
+ 	scripts/checks.m4 \
+ 	scripts/common.m4 \
+ 	scripts/attributes.m4 \
++	scripts/ssl.m4 \
+ 	doc/main.xml \
+ 	doc/http.xml \
+ 	doc/torrent.xml \
+diff --git a/configure.ac b/configure.ac
+index 4ed08124..620ca552 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -17,7 +17,7 @@ AC_SUBST(LIBTORRENT_CURRENT)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_INFO)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_NO)
+ 
+-AM_INIT_AUTOMAKE
++AM_INIT_AUTOMAKE([serial-tests])
+ AC_CONFIG_HEADERS(config.h)
+ 
+ AC_PROG_CXX
+@@ -35,7 +35,6 @@ RAK_ENABLE_EXTRA_DEBUG
+ RAK_ENABLE_WERROR
+ 
+ RAK_CHECK_CXX11
+-RAK_CHECK_TR1_LIB
+ 
+ AC_SYS_LARGEFILE
+ 
+@@ -67,41 +66,8 @@ CFLAGS="$PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CFLAGS"
+ CXXFLAGS="$PTHREAD_CFLAGS $CPPUNIT_CFLAGS $CXXFLAGS"
+ LIBS="$PTHREAD_LIBS $CPPUNIT_LIBS $LIBS"
+ 
+-AC_ARG_ENABLE(openssl,
+-  [  --disable-openssl       Don't use OpenSSL's SHA1 implementation.],
+-  [
+-    if test "$enableval" = "yes"; then
+-dnl move to scripts.
+-      PKG_CHECK_MODULES(OPENSSL, libcrypto,
+-        CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
+-        LIBS="$LIBS $OPENSSL_LIBS")
+-
+-      AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
+-      AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
+-      AC_CHECK_LIB([crypto], [DH_set0_pqg], [AC_DEFINE(USE_OPENSSL_1_1, 1, Using OpenSSL 1.1.)])
+-
+-    else
+-      AC_DEFINE(USE_NSS_SHA, 1, Using Mozilla's SHA1 implementation.)
+-    fi
+-  ],[
+-    PKG_CHECK_MODULES(OPENSSL, libcrypto,
+-      CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
+-      LIBS="$LIBS $OPENSSL_LIBS")
+-
+-    AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
+-    AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
+-    AC_CHECK_LIB([crypto], [DH_set0_pqg], [AC_DEFINE(USE_OPENSSL_1_1, 1, Using OpenSSL 1.1.)])
+-  ]
+-)
+-
+-AC_ARG_ENABLE(cyrus-rc4,
+-  [  --enable-cyrus-rc4=PFX  Use Cyrus RC4 implementation.],
+-  [
+-    CXXFLAGS="$CXXFLAGS -I${enableval}/include";
+-    LIBS="$LIBS -lrc4 -L${enableval}/lib"
+-    AC_DEFINE(USE_CYRUS_RC4, 1, Using Cyrus RC4 implementation.)
+-  ]
+-)
++TORRENT_ARG_OPENSSL
++TORRENT_ARG_CYRUS_RC4
+ 
+ AC_CHECK_FUNCS(posix_memalign)
+ 
+diff --git a/extra/corrupt_file.cc b/extra/corrupt_file.cc
+index 2a818cc7..7ae906e6 100644
+--- a/extra/corrupt_file.cc
++++ b/extra/corrupt_file.cc
+@@ -1,6 +1,6 @@
+ #include <iostream>
+ #include <stdexcept>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+diff --git a/rak/file_stat.h b/rak/file_stat.h
+index 5ad45e8f..f1ad8c2b 100644
+--- a/rak/file_stat.h
++++ b/rak/file_stat.h
+@@ -38,7 +38,7 @@
+ #define RAK_FILE_STAT_H
+ 
+ #include <string>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <sys/stat.h>
+ 
+ namespace rak {
+diff --git a/rak/fs_stat.h b/rak/fs_stat.h
+index 5e844277..2d73ff1b 100644
+--- a/rak/fs_stat.h
++++ b/rak/fs_stat.h
+@@ -38,7 +38,7 @@
+ #define RAK_FS_STAT_H
+ 
+ #include <string>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ #include <rak/error_number.h>
+ 
+diff --git a/rak/partial_queue.h b/rak/partial_queue.h
+index 6650a633..1abfdddf 100644
+--- a/rak/partial_queue.h
++++ b/rak/partial_queue.h
+@@ -39,7 +39,7 @@
+ 
+ #include <cstring>
+ #include <stdexcept>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ namespace rak {
+ 
+diff --git a/rak/path.h b/rak/path.h
+index bfe8ccc1..64daf355 100644
+--- a/rak/path.h
++++ b/rak/path.h
+@@ -99,7 +99,7 @@ path_expand(const char* src, char* first, char* last) {
+     src++;
+   }
+ 
+-  return std::max(first + strlcpy(first, src, std::distance(first, last)), last);
++  return std::min(first + strlcpy(first, src, std::distance(first, last)), last);
+ }
+ 
+ }
+diff --git a/rak/priority_queue_default.h b/rak/priority_queue_default.h
+index 01a0070e..a7bba0ce 100644
+--- a/rak/priority_queue_default.h
++++ b/rak/priority_queue_default.h
+@@ -37,7 +37,7 @@
+ #ifndef RAK_PRIORITY_QUEUE_DEFAULT_H
+ #define RAK_PRIORITY_QUEUE_DEFAULT_H
+ 
+-#include lt_tr1_functional
++#include <functional>
+ #include <rak/allocators.h>
+ #include <rak/priority_queue.h>
+ #include <rak/timer.h>
+diff --git a/rak/socket_address.h b/rak/socket_address.h
+index 961c53b2..8eb60116 100644
+--- a/rak/socket_address.h
++++ b/rak/socket_address.h
+@@ -47,9 +47,12 @@
+ #ifndef RAK_SOCKET_ADDRESS_H
+ #define RAK_SOCKET_ADDRESS_H
+ 
++#include <cinttypes>
++#include <cstdint>
+ #include <cstring>
+-#include <string>
+ #include <stdexcept>
++#include <string>
++
+ #include <arpa/inet.h>
+ #include <netinet/in.h>
+ #include <sys/types.h>
+@@ -84,7 +87,6 @@ public:
+ 
+   bool                is_valid_inet_class() const             { return family() == af_inet || family() == af_inet6; }
+ 
+-  // Should we need to set AF_UNSPEC?
+   void                clear()                                 { std::memset(this, 0, sizeof(socket_address)); set_family(); }
+ 
+   sa_family_t         family() const                          { return m_sockaddr.sa_family; }
+@@ -124,6 +126,7 @@ public:
+   // extranous bytes and ensure it does not go beyond the size of this
+   // struct.
+   void                copy(const socket_address& src, size_t length);
++  void                copy_sockaddr(const sockaddr* src);
+ 
+   static socket_address*       cast_from(sockaddr* sa)        { return reinterpret_cast<socket_address*>(sa); }
+   static const socket_address* cast_from(const sockaddr* sa)  { return reinterpret_cast<const socket_address*>(sa); }
+@@ -220,6 +223,8 @@ public:
+ 
+   void                set_address_any()                       { set_port(0); set_address(in6addr_any); }
+ 
++  std::string         pretty_address_str() const;
++
+   sa_family_t         family() const                          { return m_sockaddr.sin6_family; }
+   void                set_family()                            { m_sockaddr.sin6_family = AF_INET6; }
+ 
+@@ -340,7 +345,7 @@ socket_address::pretty_address_str() const {
+   case af_inet:
+     return sa_inet()->address_str();
+   case af_inet6:
+-    return sa_inet6()->address_str();
++    return sa_inet6()->pretty_address_str();
+   case af_unspec:
+     return std::string("unspec");
+   default:
+@@ -380,13 +385,16 @@ socket_address::length() const {
+ inline void
+ socket_address::copy(const socket_address& src, size_t length) {
+   length = std::min(length, sizeof(socket_address));
+-  
+-  // Does this get properly optimized?
++
+   std::memset(this, 0, sizeof(socket_address));
+   std::memcpy(this, &src, length);
+ }
+ 
+-// Should we be able to compare af_unspec?
++inline void
++socket_address::copy_sockaddr(const sockaddr* src) {
++  std::memset(this, 0, sizeof(socket_address));
++  std::memcpy(this, src, socket_address::cast_from(src)->length());
++}
+ 
+ inline bool
+ socket_address::operator == (const socket_address& rhs) const {
+@@ -488,6 +496,35 @@ socket_address_inet6::set_address_c_str(const char* a) {
+   return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
+ }
+ 
++inline std::string
++socket_address_inet6::pretty_address_str() const {
++  char buf[INET6_ADDRSTRLEN + 2 + 6];
++
++  if (inet_ntop(family(), &m_sockaddr.sin6_addr, buf + 1, INET6_ADDRSTRLEN) == NULL)
++    return std::string();
++
++  buf[0] = '[';
++
++  char* last_char = (char*)std::memchr(buf + 1, 0, INET6_ADDRSTRLEN);
++
++  // TODO: Throw exception here.
++
++  if (last_char == NULL || last_char >= buf + 1 + INET6_ADDRSTRLEN)
++    throw std::logic_error("inet_ntop for inet6 returned bad buffer");
++
++  *(last_char++) = ']';
++
++  if (!is_port_any()) {
++    if (snprintf(last_char, 7, ":%" PRIu16, port()) == -1)
++      return std::string("error"); // TODO: Throw here.
++
++  } else {
++    *last_char = '\0';
++  }
++
++  return std::string(buf);
++}
++
+ inline socket_address
+ socket_address_inet6::normalize_address() const {
+   const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
+diff --git a/rak/timer.h b/rak/timer.h
+index e25ad2e6..842a2e53 100644
+--- a/rak/timer.h
++++ b/rak/timer.h
+@@ -38,7 +38,7 @@
+ #define RAK_TIMER_H
+ 
+ #include <limits>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <sys/time.h>
+ 
+ namespace rak {
+diff --git a/scripts/checks.m4 b/scripts/checks.m4
+index 83be8461..98ef17f8 100644
+--- a/scripts/checks.m4
++++ b/scripts/checks.m4
+@@ -88,6 +88,7 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
+     [
+       AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
+       AC_MSG_RESULT(yes)
++      TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ], [
+       AC_MSG_RESULT(no)
+     ])
+@@ -137,7 +138,6 @@ AC_DEFUN([TORRENT_WITH_KQUEUE], [
+     [
+         if test "$withval" = "yes"; then
+           TORRENT_CHECK_KQUEUE
+-          TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+         fi
+     ])
+ ])
+@@ -149,11 +149,9 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_KQUEUE
+-        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+       fi
+     ], [
+         TORRENT_CHECK_KQUEUE
+-        TORRENT_CHECK_KQUEUE_SOCKET_ONLY
+     ])
+ ])
+ 
+diff --git a/scripts/rak_cxx.m4 b/scripts/rak_cxx.m4
+index 3660f3a7..0db61b83 100644
+--- a/scripts/rak_cxx.m4
++++ b/scripts/rak_cxx.m4
+@@ -12,50 +12,3 @@ AC_DEFUN([RAK_CHECK_CXX11], [
+     ]
+   )
+ ])
+-
+-AC_DEFUN([RAK_CHECK_TR1_LIB], [
+-  AC_LANG_PUSH(C++)
+-  AC_MSG_CHECKING(should use TR1 headers)
+-
+-  AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+-      #include <unordered_map>
+-      class Foo; typedef std::unordered_map<Foo*, int> Bar;
+-      Bar b1;
+-      ])
+-  ], [
+-      AC_MSG_RESULT(no)
+-      AC_DEFINE(USE_TR1_LIB, 0, Define to 1 if you need to use TR1 containers.)
+-
+-      AC_DEFINE([lt_tr1_array], [<array>], [TR1 array])
+-      AC_DEFINE([lt_tr1_functional], [<functional>], [TR1 functional])
+-      AC_DEFINE([lt_tr1_memory], [<memory>], [TR1 memory])
+-      AC_DEFINE([lt_tr1_unordered_map], [<unordered_map>], [TR1 unordered_map])
+-
+-  ], [
+-    AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+-        #include <tr1/unordered_map>
+-        class Foo; typedef std::tr1::unordered_map<Foo*, int> Bar;
+-        Bar b1;
+-        ])
+-    ], [
+-        AC_MSG_RESULT([yes])
+-        AC_DEFINE(USE_TR1_LIB, 1, Define to 1 if you need to use TR1 containers.)
+-
+-        AC_DEFINE([lt_tr1_array], [<tr1/array>], [TR1 array])
+-        AC_DEFINE([lt_tr1_functional], [<tr1/functional>], [TR1 functional])
+-        AC_DEFINE([lt_tr1_memory], [<tr1/memory>], [TR1 memory])
+-        AC_DEFINE([lt_tr1_unordered_map], [<tr1/unordered_map>], [TR1 unordered_map])
+-
+-    ], [
+-        AC_MSG_ERROR([No support for C++11 standard library nor TR1 extensions found.])
+-    ])
+-  ])
+-
+-  AH_VERBATIM(lt_tr1_zzz, [
+-#if USE_TR1_LIB == 1
+-namespace std { namespace tr1 {} using namespace tr1; }
+-#endif
+-])
+-
+-  AC_LANG_POP(C++)
+-])
+diff --git a/scripts/ssl.m4 b/scripts/ssl.m4
+new file mode 100644
+index 00000000..f07349a1
+--- /dev/null
++++ b/scripts/ssl.m4
+@@ -0,0 +1,38 @@
++AC_DEFUN([TORRENT_CHECK_OPENSSL],
++  [
++    PKG_CHECK_MODULES(OPENSSL, libcrypto,
++      CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
++      LIBS="$LIBS $OPENSSL_LIBS")
++
++    AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
++    AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
++  ]
++)
++
++AC_DEFUN([TORRENT_ARG_OPENSSL],
++  [
++    AC_ARG_ENABLE(openssl,
++      [  --disable-openssl       Don't use OpenSSL's SHA1 implementation.],
++      [
++        if test "$enableval" = "yes"; then
++          TORRENT_CHECK_OPENSSL
++        else
++          AC_DEFINE(USE_NSS_SHA, 1, Using Mozilla's SHA1 implementation.)
++        fi
++      ],[
++        TORRENT_CHECK_OPENSSL
++      ])
++  ]
++)
++
++AC_DEFUN([TORRENT_ARG_CYRUS_RC4],
++  [
++    AC_ARG_ENABLE(cyrus-rc4,
++      [  --enable-cyrus-rc4=PFX  Use Cyrus RC4 implementation.],
++      [
++        CXXFLAGS="$CXXFLAGS -I${enableval}/include";
++        LIBS="$LIBS -lrc4 -L${enableval}/lib"
++        AC_DEFINE(USE_CYRUS_RC4, 1, Using Cyrus RC4 implementation.)
++      ])
++  ]
++)
+diff --git a/src/data/chunk_list.cc b/src/data/chunk_list.cc
+index 00abbc2a..7622b825 100644
+--- a/src/data/chunk_list.cc
++++ b/src/data/chunk_list.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include <rak/error_number.h>
+ #include <rak/functional.h>
+ 
+diff --git a/src/data/chunk_list.h b/src/data/chunk_list.h
+index b6ff4cdb..4b40dc42 100644
+--- a/src/data/chunk_list.h
++++ b/src/data/chunk_list.h
+@@ -37,9 +37,9 @@
+ #ifndef LIBTORRENT_DATA_CHUNK_LIST_H
+ #define LIBTORRENT_DATA_CHUNK_LIST_H
+ 
++#include <functional>
+ #include <string>
+ #include <vector>
+-#include lt_tr1_functional
+ 
+ #include "chunk.h"
+ #include "chunk_handle.h"
+diff --git a/src/data/chunk_list_node.h b/src/data/chunk_list_node.h
+index 76de6671..95e4ed4f 100644
+--- a/src/data/chunk_list_node.h
++++ b/src/data/chunk_list_node.h
+@@ -37,7 +37,7 @@
+ #ifndef LIBTORRENT_DATA_CHUNK_LIST_NODE_H
+ #define LIBTORRENT_DATA_CHUNK_LIST_NODE_H
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <rak/timer.h>
+ 
+ namespace torrent {
+diff --git a/src/data/hash_check_queue.h b/src/data/hash_check_queue.h
+index b933f137..9f28c118 100644
+--- a/src/data/hash_check_queue.h
++++ b/src/data/hash_check_queue.h
+@@ -38,8 +38,8 @@
+ #define LIBTORRENT_DATA_HASH_CHECK_QUEUE_H
+ 
+ #include <deque>
++#include <functional>
+ #include <pthread.h>
+-#include lt_tr1_functional
+ 
+ #include "rak/allocators.h"
+ 
+diff --git a/src/data/hash_queue.cc b/src/data/hash_queue.cc
+index 7dffaee4..3f54892b 100644
+--- a/src/data/hash_queue.cc
++++ b/src/data/hash_queue.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include <functional>
+ #include <rak/functional.h>
+ #include <unistd.h>
+diff --git a/src/data/hash_queue.h b/src/data/hash_queue.h
+index 6885a383..3a841967 100644
+--- a/src/data/hash_queue.h
++++ b/src/data/hash_queue.h
+@@ -38,9 +38,9 @@
+ #define LIBTORRENT_DATA_HASH_QUEUE_H
+ 
+ #include <deque>
++#include <functional>
+ #include <map>
+ #include <pthread.h>
+-#include lt_tr1_functional
+ 
+ #include "torrent/hash_string.h"
+ #include "hash_queue_node.h"
+diff --git a/src/data/hash_queue_node.h b/src/data/hash_queue_node.h
+index aa59a062..c8367b7c 100644
+--- a/src/data/hash_queue_node.h
++++ b/src/data/hash_queue_node.h
+@@ -37,9 +37,9 @@
+ #ifndef LIBTORRENT_DATA_HASH_QUEUE_NODE_H
+ #define LIBTORRENT_DATA_HASH_QUEUE_NODE_H
+ 
++#include <cinttypes>
++#include <functional>
+ #include <string>
+-#include lt_tr1_functional
+-#include <inttypes.h>
+ 
+ #include "chunk_handle.h"
+ #include "hash_chunk.h"
+diff --git a/src/data/hash_torrent.cc b/src/data/hash_torrent.cc
+index 758a10fa..e803f1cb 100644
+--- a/src/data/hash_torrent.cc
++++ b/src/data/hash_torrent.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include "data/chunk_list.h"
+ #include "torrent/exceptions.h"
+ #include "torrent/data/download_data.h"
+diff --git a/src/data/hash_torrent.h b/src/data/hash_torrent.h
+index 6af643f2..9ce2f100 100644
+--- a/src/data/hash_torrent.h
++++ b/src/data/hash_torrent.h
+@@ -37,9 +37,9 @@
+ #ifndef LIBTORRENT_DATA_HASH_TORRENT_H
+ #define LIBTORRENT_DATA_HASH_TORRENT_H
+ 
++#include <cinttypes>
++#include <functional>
+ #include <string>
+-#include <inttypes.h>
+-#include lt_tr1_functional
+ #include <rak/priority_queue_default.h>
+ 
+ #include "data/chunk_handle.h"
+diff --git a/src/data/memory_chunk.h b/src/data/memory_chunk.h
+index cc32eff1..d2b5565d 100644
+--- a/src/data/memory_chunk.h
++++ b/src/data/memory_chunk.h
+@@ -38,7 +38,7 @@
+ #define LIBTORRENT_DATA_MEMORY_CHUNK_H
+ 
+ #include <algorithm>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <sys/mman.h>
+ #include <cstddef>
+ 
+diff --git a/src/data/socket_file.h b/src/data/socket_file.h
+index 7b27af8c..d25c4a44 100644
+--- a/src/data/socket_file.h
++++ b/src/data/socket_file.h
+@@ -38,7 +38,7 @@
+ #define LIBTORRENT_SOCKET_FILE_H
+ 
+ #include <string>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ 
+diff --git a/src/dht/dht_hash_map.h b/src/dht/dht_hash_map.h
+index 140f070b..1506db56 100644
+--- a/src/dht/dht_hash_map.h
++++ b/src/dht/dht_hash_map.h
+@@ -39,20 +39,14 @@
+ 
+ #include "config.h"
+ 
+-#if HAVE_TR1
+-#include <lt_tr1_unordered_map>
+-#else
+-#include <map>
+-#endif
+-
+-#include "torrent/hash_string.h"
++#include <unordered_map>
+ 
+ #include "dht_node.h"
+ #include "dht_tracker.h"
++#include "torrent/hash_string.h"
+ 
+ namespace torrent {
+ 
+-#if HAVE_TR1
+ // Hash functions for HashString keys, and dereferencing HashString pointers.
+ 
+ // Since the first few bits are very similar if not identical (since the IDs
+@@ -142,53 +136,6 @@ public:
+ 
+ };
+ 
+-#else
+-
+-// Compare HashString pointers by dereferencing them.
+-struct hashstring_ptr_less : public std::binary_function<const HashString*, const HashString*, bool> {
+-  size_t operator () (const HashString* one, const HashString* two) const 
+-  { return *one < *two; }
+-};
+-
+-class DhtNodeList : public std::map<const HashString*, DhtNode*, hashstring_ptr_less> {
+-public:
+-  typedef std::map<const HashString*, DhtNode*, hashstring_ptr_less> base_type;
+-
+-  // Define accessor iterator with more convenient access to the key and
+-  // element values.  Allows changing the map definition more easily if needed.
+-  template<typename T>
+-  struct accessor_wrapper : public T {
+-    accessor_wrapper(const T& itr) : T(itr) { }
+-
+-    const HashString&    id() const    { return *(**this).first; }
+-    DhtNode*             node() const  { return (**this).second; }
+-  };
+-
+-  typedef accessor_wrapper<const_iterator>  const_accessor;
+-  typedef accessor_wrapper<iterator>        accessor;
+-
+-  DhtNode*            add_node(DhtNode* n);
+-
+-};
+-
+-class DhtTrackerList : public std::map<HashString, DhtTracker*> {
+-public:
+-  typedef std::map<HashString, DhtTracker*> base_type;
+-
+-  template<typename T>
+-  struct accessor_wrapper : public T {
+-    accessor_wrapper(const T& itr) : T(itr) { }
+-
+-    const HashString&    id() const       { return (**this).first; }
+-    DhtTracker*          tracker() const  { return (**this).second; }
+-  };
+-
+-  typedef accessor_wrapper<const_iterator>  const_accessor;
+-  typedef accessor_wrapper<iterator>        accessor;
+-
+-};
+-#endif // HAVE_TR1
+-
+ inline
+ DhtNode* DhtNodeList::add_node(DhtNode* n) {
+   insert(std::make_pair((const HashString*)n, (DhtNode*)n));
+diff --git a/src/download/chunk_selector.h b/src/download/chunk_selector.h
+index 52c31fd5..ab1b8c17 100644
+--- a/src/download/chunk_selector.h
++++ b/src/download/chunk_selector.h
+@@ -37,7 +37,7 @@
+ #ifndef LIBTORRENT_DOWNLOAD_CHUNK_SELECTOR_H
+ #define LIBTORRENT_DOWNLOAD_CHUNK_SELECTOR_H
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <rak/partial_queue.h>
+ 
+ #include "torrent/bitfield.h"
+diff --git a/src/download/chunk_statistics.h b/src/download/chunk_statistics.h
+index 816ec6c9..62f76c5a 100644
+--- a/src/download/chunk_statistics.h
++++ b/src/download/chunk_statistics.h
+@@ -37,7 +37,7 @@
+ #ifndef LIBTORRENT_DOWNLOAD_CHUNK_STATISTICS_H
+ #define LIBTORRENT_DOWNLOAD_CHUNK_STATISTICS_H
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <vector>
+ 
+ namespace torrent {
+diff --git a/src/download/delegator.cc b/src/download/delegator.cc
+index 711cd461..27ae42ec 100644
+--- a/src/download/delegator.cc
++++ b/src/download/delegator.cc
+@@ -39,7 +39,7 @@
+ #include "config.h"
+ 
+ #include <algorithm>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ #include "torrent/exceptions.h"
+ #include "torrent/bitfield.h"
+diff --git a/src/download/delegator.h b/src/download/delegator.h
+index 3b997b81..b75d4c2a 100644
+--- a/src/download/delegator.h
++++ b/src/download/delegator.h
+@@ -37,9 +37,9 @@
+ #ifndef LIBTORRENT_DELEGATOR_H
+ #define LIBTORRENT_DELEGATOR_H
+ 
++#include <functional>
+ #include <string>
+ #include <vector>
+-#include lt_tr1_functional
+ 
+ #include "torrent/data/transfer_list.h"
+ 
+diff --git a/src/download/download_constructor.h b/src/download/download_constructor.h
+index 7d43aba3..6a09b7f1 100644
+--- a/src/download/download_constructor.h
++++ b/src/download/download_constructor.h
+@@ -39,7 +39,7 @@
+ 
+ #include <list>
+ #include <string>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ namespace torrent {
+ 
+diff --git a/src/globals.cc b/src/globals.cc
+index 88130c19..20644fbd 100644
+--- a/src/globals.cc
++++ b/src/globals.cc
+@@ -37,11 +37,24 @@
+ #include "config.h"
+ 
+ #include "globals.h"
+-#include "torrent/common.h"
++#include "manager.h"
++#include "torrent/connection_manager.h"
++#include "torrent/event.h"
++#include "torrent/poll.h"
+ 
+ namespace torrent {
+ 
+ LIBTORRENT_EXPORT rak::priority_queue_default taskScheduler;
+ LIBTORRENT_EXPORT rak::timer                  cachedTime;
+ 
++void poll_event_open(Event* event) { manager->poll()->open(event); manager->connection_manager()->inc_socket_count(); }
++void poll_event_close(Event* event) { manager->poll()->close(event); manager->connection_manager()->dec_socket_count(); }
++void poll_event_closed(Event* event) { manager->poll()->closed(event); manager->connection_manager()->dec_socket_count(); }
++void poll_event_insert_read(Event* event) { manager->poll()->insert_read(event); }
++void poll_event_insert_write(Event* event) { manager->poll()->insert_write(event); }
++void poll_event_insert_error(Event* event) { manager->poll()->insert_error(event); }
++void poll_event_remove_read(Event* event) { manager->poll()->remove_read(event); }
++void poll_event_remove_write(Event* event) { manager->poll()->remove_write(event); }
++void poll_event_remove_error(Event* event) { manager->poll()->remove_error(event); }
++
+ }
+diff --git a/src/globals.h b/src/globals.h
+index 564ac86d..e9fe1177 100644
+--- a/src/globals.h
++++ b/src/globals.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_GLOBALS_H
+ #define LIBTORRENT_GLOBALS_H
+ 
+diff --git a/src/manager.cc b/src/manager.cc
+index c503974d..11ef4b0f 100644
+--- a/src/manager.cc
++++ b/src/manager.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"
+ 
+ #include "torrent/exceptions.h"
+diff --git a/src/net/Makefile.am b/src/net/Makefile.am
+index fb4da4f3..e3a8c7e1 100644
+--- a/src/net/Makefile.am
++++ b/src/net/Makefile.am
+@@ -15,6 +15,8 @@ libsub_net_la_SOURCES = \
+ 	socket_datagram.h \
+ 	socket_fd.cc \
+ 	socket_fd.h \
++	socket_listen.cc \
++	socket_listen.h \
+ 	socket_set.cc \
+ 	socket_set.h \
+ 	socket_stream.cc \
+diff --git a/src/net/data_buffer.h b/src/net/data_buffer.h
+index d35cdc48..5dd0cb30 100644
+--- a/src/net/data_buffer.h
++++ b/src/net/data_buffer.h
+@@ -38,7 +38,7 @@
+ #define LIBTORRENT_NET_DATA_BUFFER_H
+ 
+ #include <memory>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ namespace torrent {
+ 
+diff --git a/src/net/listen.cc b/src/net/listen.cc
+index d424e94c..61fedbf8 100644
+--- a/src/net/listen.cc
++++ b/src/net/listen.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
+@@ -95,7 +59,7 @@ Listen::open(uint16_t first, uint16_t last, int backlog, const rak::socket_addre
+       manager->poll()->insert_read(this);
+       manager->poll()->insert_error(this);
+ 
+-      lt_log_print(LOG_CONNECTION_INFO, "listen port %" PRIu16 " opened with backlog set to %i",
++      lt_log_print(LOG_CONNECTION_LISTEN, "listen port %" PRIu16 " opened with backlog set to %i",
+                    m_port, backlog);
+ 
+       return true;
+@@ -107,7 +71,7 @@ Listen::open(uint16_t first, uint16_t last, int backlog, const rak::socket_addre
+   get_fd().close();
+   get_fd().clear();
+ 
+-  lt_log_print(LOG_CONNECTION_INFO, "failed to open listen port");
++  lt_log_print(LOG_CONNECTION_LISTEN, "failed to open listen port");
+ 
+   return false;
+ }
+diff --git a/src/net/listen.h b/src/net/listen.h
+index b3c845aa..58c06c7e 100644
+--- a/src/net/listen.h
++++ b/src/net/listen.h
+@@ -37,8 +37,8 @@
+ #ifndef LIBTORRENT_LISTEN_H
+ #define LIBTORRENT_LISTEN_H
+ 
+-#include <inttypes.h>
+-#include lt_tr1_functional
++#include <cinttypes>
++#include <functional>
+ #include <rak/socket_address.h>
+ 
+ #include "socket_base.h"
+diff --git a/src/net/protocol_buffer.h b/src/net/protocol_buffer.h
+index b64d47ea..f9711ded 100644
+--- a/src/net/protocol_buffer.h
++++ b/src/net/protocol_buffer.h
+@@ -38,7 +38,7 @@
+ #define LIBTORRENT_NET_PROTOCOL_BUFFER_H
+ 
+ #include <memory>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <netinet/in.h>
+ 
+ #include "torrent/exceptions.h"
+diff --git a/src/net/socket_base.h b/src/net/socket_base.h
+index 02c9497d..20ae1d9f 100644
+--- a/src/net/socket_base.h
++++ b/src/net/socket_base.h
+@@ -38,7 +38,7 @@
+ #define LIBTORRENT_NET_SOCKET_BASE_H
+ 
+ #include <list>
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ #include "torrent/event.h"
+ #include "socket_fd.h"
+diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc
+index f04059f6..c36ff4b9 100644
+--- a/src/net/socket_fd.cc
++++ b/src/net/socket_fd.cc
+@@ -210,6 +210,11 @@ SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
+   return !::bind(m_fd, sa.c_sockaddr(), length);
+ }
+ 
++bool
++SocketFd::bind_sa(const sockaddr* sa) {
++  return bind(*rak::socket_address::cast_from(sa));
++}
++
+ bool
+ SocketFd::connect(const rak::socket_address& sa) {
+   check_valid();
+@@ -222,6 +227,11 @@ SocketFd::connect(const rak::socket_address& sa) {
+   return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
+ }
+ 
++bool
++SocketFd::connect_sa(const sockaddr* sa) {
++  return connect(*rak::socket_address::cast_from(sa));
++}
++
+ bool
+ SocketFd::getsockname(rak::socket_address *sa) {
+   check_valid();
+diff --git a/src/net/socket_fd.h b/src/net/socket_fd.h
+index 2329b4e9..4db0087b 100644
+--- a/src/net/socket_fd.h
++++ b/src/net/socket_fd.h
+@@ -39,6 +39,8 @@
+ 
+ #include <unistd.h>
+ 
++struct sockaddr;
++
+ namespace rak {
+   class socket_address;
+ }
+@@ -80,7 +82,11 @@ public:
+ 
+   bool                bind(const rak::socket_address& sa);
+   bool                bind(const rak::socket_address& sa, unsigned int length);
++  bool                bind_sa(const sockaddr* sa);
++
+   bool                connect(const rak::socket_address& sa);
++  bool                connect_sa(const sockaddr* sa);
++
+   bool                getsockname(rak::socket_address* sa);
+ 
+   bool                listen(int size);
+diff --git a/src/net/socket_listen.cc b/src/net/socket_listen.cc
+new file mode 100644
+index 00000000..97f006e0
+--- /dev/null
++++ b/src/net/socket_listen.cc
+@@ -0,0 +1,137 @@
++#include "config.h"
++
++#include "socket_listen.h"
++
++#include <algorithm>
++
++#include "torrent/connection_manager.h"
++#include "torrent/exceptions.h"
++#include "torrent/utils/log.h"
++#include "torrent/utils/random.h"
++
++#define LT_LOG_SAP(log_fmt, sap, ...)                                   \
++  lt_log_print(LOG_CONNECTION_LISTEN, "listen->%s: " log_fmt, sap_pretty_str(sap).c_str(), __VA_ARGS__);
++
++namespace torrent {
++
++socket_listen::socket_listen() : m_backlog(SOMAXCONN) {
++}
++
++void
++socket_listen::set_backlog(int backlog) {
++  if (backlog < 0 || backlog > SOMAXCONN)
++    throw internal_error("Could not set socket_listen backlog, out-of-range value.");
++
++  m_backlog = backlog;
++}
++
++bool
++socket_listen::open(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, uint16_t start_port, fd_flags open_flags) {
++  if (is_open())
++    throw internal_error("socket_listen::open: already open");
++
++  if (!(sap_is_inet(sap) || sap_is_inet6(sap)) || sap_is_v4mapped(sap) || !sap_is_port_any(sap) || sap_is_broadcast(sap))
++    throw internal_error("socket_listen::open: socket address must be inet/inet6 with no port, and not v4mapped nor broadcast: " + sap_pretty_str(sap));
++
++  if (sap_is_inet(sap) && !(open_flags & fd_flag_v4only))
++    throw internal_error("socket_listen::open: socket address is inet without v4only flag");
++
++  if (first_port == 0 || last_port == 0 || start_port == 0 ||
++      !(first_port <= last_port && first_port <= start_port && start_port <= last_port))
++    throw internal_error("socket_listen::open: port range not valid");
++
++  int fd = fd_open(open_flags);
++
++  if (fd == -1) {
++    LT_LOG_SAP("open failed (flags:0x%x errno:%i message:'%s')", sap, open_flags, errno, std::strerror(errno));
++    return false;
++  }
++
++  uint16_t p = start_port;
++
++  do {
++    if (m_open_port(fd, sap, p))
++      return is_open();
++
++    if (p == last_port)
++      p = first_port;
++    else
++      p++;
++  } while (p != start_port);
++
++  LT_LOG_SAP("listen ports exhausted (fd:%i first_port:%" PRIu16 " last_port:%" PRIu16 ")",
++             sap, fd, first_port, last_port);
++  fd_close(fd);
++  return false;
++}
++
++bool
++socket_listen::open_randomize(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, fd_flags open_flags) {
++  if (last_port < first_port)
++    throw internal_error("socket_listen::open_randomize: port range not valid");
++
++  return open(std::move(sap), first_port, last_port, random_uniform_uint16(first_port, last_port), open_flags);
++}
++
++bool
++socket_listen::open_sequential(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, fd_flags open_flags) {
++  return open(std::move(sap), first_port, last_port, first_port, open_flags);
++}
++
++void
++socket_listen::close() {
++  if (!is_open())
++    return;
++
++  torrent::poll_event_closed(this);
++
++  fd_close(file_descriptor());
++  set_file_descriptor(-1);
++  m_socket_address.reset();
++}
++
++void
++socket_listen::event_read() {
++}
++
++void
++socket_listen::event_error() {
++}
++
++// Returns true if open is successful or if we cannot bind to the
++// address, returns false if other ports can be used.
++bool
++socket_listen::m_open_port(int fd, sa_unique_ptr& sap, uint16_t port) {
++  sap_set_port(sap, port);
++
++  if (!fd_bind(fd, sap.get())) {
++    if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
++      LT_LOG_SAP("listen address not usable (fd:%i errno:%i message:'%s')",
++                 sap, fd, errno, std::strerror(errno));
++      fd_close(fd);
++      return true;
++    }
++
++    return false;
++  }
++
++  if (!fd_listen(fd, m_backlog)) {
++    LT_LOG_SAP("call to listen failed (fd:%i backlog:%i errno:%i message:'%s')",
++               sap, fd, m_backlog, errno, std::strerror(errno));
++    fd_close(fd);
++    return true;
++  }
++
++  LT_LOG_SAP("open listen port success (fd:%i backlog:%i)", sap, fd, m_backlog);
++
++  m_fileDesc = fd;
++  m_socket_address.swap(sap);
++
++  torrent::poll_event_open(this);
++  torrent::poll_event_insert_read(this);
++  torrent::poll_event_insert_error(this);
++
++  return true;
++}
++
++}
+diff --git a/src/net/socket_listen.h b/src/net/socket_listen.h
+new file mode 100644
+index 00000000..817d5fa5
+--- /dev/null
++++ b/src/net/socket_listen.h
+@@ -0,0 +1,46 @@
++#ifndef LIBTORRENT_SOCKET_LISTEN_H
++#define LIBTORRENT_SOCKET_LISTEN_H
++
++#include <cinttypes>
++#include <functional>
++
++#include "torrent/net/fd.h"
++#include "torrent/net/socket_address.h"
++#include "torrent/net/socket_event.h"
++
++namespace torrent {
++
++class socket_listen : public socket_event {
++public:
++  typedef std::function<void (int, sa_unique_ptr)> accepted_ftor;
++
++  socket_listen();
++
++  int  backlog() const;
++
++  void set_backlog(int backlog);
++  void set_slot_accepted(accepted_ftor&& ftor);
++
++  bool open(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, uint16_t start_port, fd_flags open_flags);
++  bool open_randomize(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, fd_flags open_flags);
++  bool open_sequential(sa_unique_ptr&& sap, uint16_t first_port, uint16_t last_port, fd_flags open_flags);
++  void close();
++
++  void event_read() override;
++  void event_error() override;
++
++  const char* type_name() const override { return "socket_listen"; }
++
++private:
++  bool m_open_port(int fd, sa_unique_ptr& sap, uint16_t port);
++
++  int           m_backlog;
++  accepted_ftor m_slot_accepted;
++};
++
++inline int  socket_listen::backlog() const { return m_backlog; }
++inline void socket_listen::set_slot_accepted(accepted_ftor&& ftor) { m_slot_accepted = ftor; }
++
++}
++
++#endif
+diff --git a/src/net/socket_set.h b/src/net/socket_set.h
+index 9264edf7..78443c88 100644
+--- a/src/net/socket_set.h
++++ b/src/net/socket_set.h
+@@ -39,7 +39,7 @@
+ 
+ #include <list>
+ #include <vector>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <rak/allocators.h>
+ 
+ #include "torrent/exceptions.h"
+diff --git a/src/net/throttle_node.h b/src/net/throttle_node.h
+index 77cb6cc7..5af27a22 100644
+--- a/src/net/throttle_node.h
++++ b/src/net/throttle_node.h
+@@ -37,7 +37,7 @@
+ #ifndef LIBTORRENT_NET_THROTTLE_NODE_H
+ #define LIBTORRENT_NET_THROTTLE_NODE_H
+ 
+-#include lt_tr1_functional
++#include <functional>
+ 
+ #include "torrent/rate.h"
+ 
+diff --git a/src/protocol/handshake.cc b/src/protocol/handshake.cc
+index 6b41bbe3..1b877c7a 100644
+--- a/src/protocol/handshake.cc
++++ b/src/protocol/handshake.cc
+@@ -46,6 +46,7 @@
+ #include "torrent/error.h"
+ #include "torrent/poll.h"
+ #include "torrent/throttle.h"
++#include "torrent/utils/log.h"
+ #include "utils/diffie_hellman.h"
+ 
+ #include "globals.h"
+@@ -55,6 +56,10 @@
+ #include "handshake.h"
+ #include "handshake_manager.h"
+ 
++#define LT_LOG(log_fmt, ...)                                            \
++  lt_log_print(LOG_CONNECTION_HANDSHAKE, "handshake->%s: " log_fmt,     \
++               m_address.pretty_address_str().c_str(), __VA_ARGS__);
++
+ namespace torrent {
+ 
+ const char* Handshake::m_protocol = "BitTorrent protocol";
+@@ -862,7 +867,7 @@ restart:
+     m_manager->receive_failed(this, e.type(), e.error());
+ 
+   } catch (network_error& e) {
+-    m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_error);
++    m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_read_error);
+   }
+ }
+ 
+@@ -969,7 +974,7 @@ Handshake::event_write() {
+     m_manager->receive_failed(this, e.type(), e.error());
+ 
+   } catch (network_error& e) {
+-    m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_error);
++    m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_write_error);
+   }
+ }
+ 
+@@ -1070,7 +1075,7 @@ Handshake::prepare_peer_info() {
+     m_peerInfo = m_download->peer_list()->connected(m_address.c_sockaddr(), PeerList::connect_incoming);
+ 
+     if (m_peerInfo == NULL)
+-      throw handshake_error(ConnectionManager::handshake_failed, e_handshake_network_error);
++      throw handshake_error(ConnectionManager::handshake_failed, e_handshake_no_peer_info);
+ 
+     if (m_peerInfo->failed_counter() > m_manager->max_failed)
+       throw handshake_error(ConnectionManager::handshake_dropped, e_handshake_toomanyfailed);
+@@ -1221,7 +1226,7 @@ Handshake::event_error() {
+   if (m_state == INACTIVE)
+     throw internal_error("Handshake::event_error() called on an inactive handshake.");
+ 
+-  m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_error);
++  m_manager->receive_failed(this, ConnectionManager::handshake_failed, e_handshake_network_socket_error);
+ }
+ 
+ }
+diff --git a/src/protocol/handshake_manager.cc b/src/protocol/handshake_manager.cc
+index b52c8d4e..99592ba8 100644
+--- a/src/protocol/handshake_manager.cc
++++ b/src/protocol/handshake_manager.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"
+ 
+ #include <rak/socket_address.h>
+@@ -54,10 +18,10 @@
+ 
+ #include "manager.h"
+ 
+-#define LT_LOG_SA(log_level, sa, log_fmt, ...)                          \
+-  lt_log_print(LOG_CONNECTION_##log_level, "handshake_manager->%s: " log_fmt, (sa)->address_str().c_str(), __VA_ARGS__);
+-#define LT_LOG_SA_C(log_level, sa, log_fmt, ...)                        \
+-  lt_log_print(LOG_CONNECTION_##log_level, "handshake_manager->%s: " log_fmt, \
++#define LT_LOG_SA(sa, log_fmt, ...)                                     \
++  lt_log_print(LOG_CONNECTION_HANDSHAKE, "handshake_manager->%s: " log_fmt, (sa)->address_str().c_str(), __VA_ARGS__);
++#define LT_LOG_SA_C(sa, log_fmt, ...)                                   \
++  lt_log_print(LOG_CONNECTION_HANDSHAKE, "handshake_manager->%s: " log_fmt, \
+                reinterpret_cast<const rak::socket_address*>(sa)->address_str().c_str(), __VA_ARGS__);
+ 
+ namespace torrent {
+@@ -122,7 +86,7 @@ HandshakeManager::add_incoming(SocketFd fd, const rak::socket_address& sa) {
+     return;
+   }
+ 
+-  LT_LOG_SA(INFO, &sa, "Adding incoming connection: fd:%i.", fd.get_fd());
++  LT_LOG_SA(&sa, "Adding incoming connection: fd:%i.", fd.get_fd());
+ 
+   manager->connection_manager()->inc_socket_count();
+ 
+@@ -183,7 +147,7 @@ HandshakeManager::create_outgoing(const rak::socket_address& sa, DownloadMain* d
+   else
+     message = ConnectionManager::handshake_outgoing;
+ 
+-  LT_LOG_SA(INFO, &sa, "Adding outcoming connection: encryption:%x message:%x.", encryptionOptions, message);
++  LT_LOG_SA(&sa, "Adding outcoming connection: encryption:%x message:%x.", encryptionOptions, message);
+   manager->connection_manager()->inc_socket_count();
+ 
+   Handshake* handshake = new Handshake(fd, this, encryptionOptions);
+@@ -213,7 +177,7 @@ HandshakeManager::receive_succeeded(Handshake* handshake) {
+                                                  handshake->extensions())) != NULL) {
+     
+     manager->client_list()->retrieve_id(&handshake->peer_info()->mutable_client_info(), handshake->peer_info()->id());
+-    LT_LOG_SA_C(INFO, handshake->peer_info()->socket_address(), "Handshake success.", 0);
++    LT_LOG_SA_C(handshake->peer_info()->socket_address(), "Handshake success.", 0);
+ 
+     pcb->peer_chunks()->set_have_timer(handshake->initialized_time());
+ 
+@@ -237,7 +201,7 @@ HandshakeManager::receive_succeeded(Handshake* handshake) {
+     else
+       reason = e_handshake_duplicate;
+ 
+-    LT_LOG_SA_C(INFO, handshake->peer_info()->socket_address(), "Handshake dropped: %s.", strerror(reason));
++    LT_LOG_SA_C(handshake->peer_info()->socket_address(), "Handshake dropped: %s.", strerror(reason));
+     handshake->destroy_connection();
+   }
+ 
+@@ -255,13 +219,13 @@ HandshakeManager::receive_failed(Handshake* handshake, int message, int error) {
+   handshake->deactivate_connection();
+   handshake->destroy_connection();
+ 
+-  LT_LOG_SA(INFO, sa, "Received error: message:%x %s.", message, strerror(error));
++  LT_LOG_SA(sa, "Received error: message:%x %s.", message, strerror(error));
+ 
+   if (handshake->encryption()->should_retry()) {
+     int retry_options = handshake->retry_options() | ConnectionManager::encryption_retrying;
+     DownloadMain* download = handshake->download();
+ 
+-    LT_LOG_SA(INFO, sa, "Retrying %s.",
++    LT_LOG_SA(sa, "Retrying %s.",
+               retry_options & ConnectionManager::encryption_try_outgoing ? "encrypted" : "plaintext");
+ 
+     create_outgoing(*sa, download, retry_options);
+diff --git a/src/protocol/handshake_manager.h b/src/protocol/handshake_manager.h
+index cfd52aa0..dc398e3e 100644
+--- a/src/protocol/handshake_manager.h
++++ b/src/protocol/handshake_manager.h
+@@ -1,45 +1,9 @@
+-// 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_NET_HANDSHAKE_MANAGER_H
+ #define LIBTORRENT_NET_HANDSHAKE_MANAGER_H
+ 
+-#include <string>
++#include <functional>
+ #include <inttypes.h>
+-#include lt_tr1_functional
++#include <string>
+ #include <rak/functional.h>
+ #include <rak/unordered_vector.h>
+ #include <rak/socket_address.h>
+diff --git a/src/protocol/peer_connection_base.cc b/src/protocol/peer_connection_base.cc
+index c02998fb..bd870425 100644
+--- a/src/protocol/peer_connection_base.cc
++++ b/src/protocol/peer_connection_base.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include <cstdio>
+ #include <fcntl.h>
+ #include <rak/error_number.h>
+diff --git a/src/protocol/request_list.cc b/src/protocol/request_list.cc
+index a4338bcb..ea5d388a 100644
+--- a/src/protocol/request_list.cc
++++ b/src/protocol/request_list.cc
+@@ -1,44 +1,8 @@
+-// 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 <functional>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <rak/functional.h>
+ 
+ #include "torrent/data/block.h"
+diff --git a/src/torrent/Makefile.am b/src/torrent/Makefile.am
+index 1bdfde3d..8cd26ce7 100644
+--- a/src/torrent/Makefile.am
++++ b/src/torrent/Makefile.am
+@@ -22,6 +22,7 @@ libsub_torrent_la_SOURCES = \
+ 	download_info.h \
+ 	error.cc \
+ 	error.h \
++	event.cc \
+ 	event.h \
+ 	exceptions.cc \
+ 	exceptions.h \
+diff --git a/src/torrent/common.h b/src/torrent/common.h
+index 3363143d..42cc3246 100644
+--- a/src/torrent/common.h
++++ b/src/torrent/common.h
+@@ -37,10 +37,13 @@
+ #ifndef LIBTORRENT_COMMON_H
+ #define LIBTORRENT_COMMON_H
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <cstddef>
+ 
+ struct sockaddr;
++struct sockaddr_in;
++struct sockaddr_in6;
++struct sockaddr_un;
+ 
+ namespace torrent {
+ 
+diff --git a/src/torrent/connection_manager.h b/src/torrent/connection_manager.h
+index 2dcf2b37..cf43b0bf 100644
+--- a/src/torrent/connection_manager.h
++++ b/src/torrent/connection_manager.h
+@@ -39,13 +39,13 @@
+ #ifndef LIBTORRENT_CONNECTION_MANAGER_H
+ #define LIBTORRENT_CONNECTION_MANAGER_H
+ 
++#include <functional>
+ #include <list>
+ #include <arpa/inet.h>
+ #include <netinet/in.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/ip.h>
+ #include <sys/socket.h>
+-#include lt_tr1_functional
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/data/download_data.h b/src/torrent/data/download_data.h
+index 2b9c9412..fc212047 100644
+--- a/src/torrent/data/download_data.h
++++ b/src/torrent/data/download_data.h
+@@ -37,7 +37,7 @@
+ #ifndef LIBTORRENT_DATA_DOWNLOAD_DATA_H
+ #define LIBTORRENT_DATA_DOWNLOAD_DATA_H
+ 
+-#include lt_tr1_functional
++#include <functional>
+ 
+ #include <torrent/common.h>
+ #include <torrent/bitfield.h>
+diff --git a/src/torrent/data/file_list.cc b/src/torrent/data/file_list.cc
+index 4721bdbd..2e334fa8 100644
+--- a/src/torrent/data/file_list.cc
++++ b/src/torrent/data/file_list.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include <algorithm>
+ #include <cstring>
+ #include <functional>
+diff --git a/src/torrent/data/transfer_list.h b/src/torrent/data/transfer_list.h
+index 0a359b5e..9813af12 100644
+--- a/src/torrent/data/transfer_list.h
++++ b/src/torrent/data/transfer_list.h
+@@ -37,9 +37,10 @@
+ #ifndef LIBTORRENT_TRANSFER_LIST_H
+ #define LIBTORRENT_TRANSFER_LIST_H
+ 
++#include <functional>
+ #include <vector>
++
+ #include <torrent/common.h>
+-#include lt_tr1_functional
+ 
+ namespace torrent {
+ 
+diff --git a/src/torrent/download.cc b/src/torrent/download.cc
+index edddedfb..f72c9351 100644
+--- a/src/torrent/download.cc
++++ b/src/torrent/download.cc
+@@ -36,9 +36,7 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ #include "data/block.h"
+ #include "data/block_list.h"
+diff --git a/src/torrent/download/choke_group.cc b/src/torrent/download/choke_group.cc
+index a1540fc1..d9b25a9c 100644
+--- a/src/torrent/download/choke_group.cc
++++ b/src/torrent/download/choke_group.cc
+@@ -37,7 +37,7 @@
+ #include "config.h"
+ 
+ #include <algorithm>
+-#include lt_tr1_functional
++#include <functional>
+ 
+ #include "choke_group.h"
+ #include "choke_queue.h"
+diff --git a/src/torrent/download/choke_group.h b/src/torrent/download/choke_group.h
+index 93fd1d02..50804b3e 100644
+--- a/src/torrent/download/choke_group.h
++++ b/src/torrent/download/choke_group.h
+@@ -39,7 +39,7 @@
+ 
+ #include <string>
+ #include <vector>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <torrent/common.h>
+ #include <torrent/download/choke_queue.h>
+ 
+diff --git a/src/torrent/download/choke_queue.cc b/src/torrent/download/choke_queue.cc
+index 3827e25e..7c00b686 100644
+--- a/src/torrent/download/choke_queue.cc
++++ b/src/torrent/download/choke_queue.cc
+@@ -37,10 +37,9 @@
+ #include "config.h"
+ 
+ #include <algorithm>
++#include <cstdlib>
+ #include <functional>
+ #include <numeric>
+-#include <cstdlib>
+-#include lt_tr1_functional
+ #include <rak/functional.h>
+ 
+ #include "protocol/peer_connection_base.h"
+diff --git a/src/torrent/download/choke_queue.h b/src/torrent/download/choke_queue.h
+index 973f6522..5e274a99 100644
+--- a/src/torrent/download/choke_queue.h
++++ b/src/torrent/download/choke_queue.h
+@@ -39,10 +39,11 @@
+ 
+ #include <torrent/common.h>
+ 
++#include <cinttypes>
++#include <functional>
+ #include <list>
+ #include <vector>
+-#include <inttypes.h>
+-#include lt_tr1_functional
++
+ #include <torrent/download/group_entry.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/download/group_entry.h b/src/torrent/download/group_entry.h
+index e167ecbb..a7c9e429 100644
+--- a/src/torrent/download/group_entry.h
++++ b/src/torrent/download/group_entry.h
+@@ -38,8 +38,9 @@
+ #define LIBTORRENT_DOWNLOAD_GROUP_ENTRY_H
+ 
+ #include <algorithm>
++#include <functional>
+ #include <vector>
+-#include lt_tr1_functional
++
+ #include <torrent/common.h>
+ #include <torrent/exceptions.h>
+ 
+diff --git a/src/torrent/download/resource_manager.cc b/src/torrent/download/resource_manager.cc
+index bc6374d2..51434c91 100644
+--- a/src/torrent/download/resource_manager.cc
++++ b/src/torrent/download/resource_manager.cc
+@@ -38,7 +38,6 @@
+ 
+ #include <algorithm>
+ #include <functional>
+-#include lt_tr1_functional
+ #include <limits>
+ #include <numeric>
+ #include <rak/functional.h>
+diff --git a/src/torrent/download/resource_manager.h b/src/torrent/download/resource_manager.h
+index b2f861af..ba61b45f 100644
+--- a/src/torrent/download/resource_manager.h
++++ b/src/torrent/download/resource_manager.h
+@@ -39,7 +39,7 @@
+ 
+ #include <string>
+ #include <vector>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/download_info.h b/src/torrent/download_info.h
+index 341e4c25..2c4dbaf2 100644
+--- a/src/torrent/download_info.h
++++ b/src/torrent/download_info.h
+@@ -37,10 +37,10 @@
+ #ifndef LIBTORRENT_DOWNLOAD_INFO_H
+ #define LIBTORRENT_DOWNLOAD_INFO_H
+ 
++#include <cinttypes>
++#include <functional>
+ #include <list>
+ #include <string>
+-#include <inttypes.h>
+-#include lt_tr1_functional
+ 
+ #include <torrent/rate.h>
+ #include <torrent/hash_string.h>
+diff --git a/src/torrent/error.cc b/src/torrent/error.cc
+index 5010c803..eea9bb83 100644
+--- a/src/torrent/error.cc
++++ b/src/torrent/error.cc
+@@ -54,11 +54,15 @@ static const char* errorStrings[e_last + 1] = {
+   "unencrypted connection rejected",    // eh_unencrypted_rejected
+   "invalid encryption method",          // eh_invalid_encryption
+   "encryption sync failed",             // eh_encryption_sync_failed
+-  "network error",                      // eh_network_error
++  "<deprecated>",                       // eh_
+   "network unreachable",                // eh_network_unreachable
+   "network timeout",                    // eh_network_timeout
+   "invalid message order",              // eh_invalid_order
+   "too many failed chunks",             // eh_toomanyfailed
++  "no peer info",                       // eh_no_peer_info
++  "network socket error",               // eh_network_socket_error
++  "network read error",                 // eh_network_read_error
++  "network write error",                // eh_network_write_error
+ 
+ //   "", // e_handshake_incoming
+ //   "", // e_handshake_outgoing
+diff --git a/src/torrent/error.h b/src/torrent/error.h
+index f3fac463..295a595b 100644
+--- a/src/torrent/error.h
++++ b/src/torrent/error.h
+@@ -55,11 +55,14 @@ const int e_handshake_invalid_value             = 8;
+ const int e_handshake_unencrypted_rejected      = 9;
+ const int e_handshake_invalid_encryption        = 10;
+ const int e_handshake_encryption_sync_failed    = 11;
+-const int e_handshake_network_error             = 12;
+ const int e_handshake_network_unreachable       = 13;
+ const int e_handshake_network_timeout           = 14;
+ const int e_handshake_invalid_order             = 15;
+ const int e_handshake_toomanyfailed             = 16;
++const int e_handshake_no_peer_info              = 17;
++const int e_handshake_network_socket_error      = 18;
++const int e_handshake_network_read_error        = 19;
++const int e_handshake_network_write_error       = 20;
+ 
+ // const int e_handshake_incoming                  = 13;
+ // const int e_handshake_outgoing                  = 14;
+@@ -69,7 +72,7 @@ const int e_handshake_toomanyfailed             = 16;
+ // const int e_handshake_retry_plaintext           = 18;
+ // const int e_handshake_retry_encrypted           = 19;
+ 
+-const int e_last                                = 16;
++const int e_last                                = 20;
+ 
+ const char* strerror(int err) LIBTORRENT_EXPORT;
+ 
+diff --git a/src/torrent/event.cc b/src/torrent/event.cc
+new file mode 100644
+index 00000000..e68974ea
+--- /dev/null
++++ b/src/torrent/event.cc
+@@ -0,0 +1,19 @@
++#include "config.h"
++
++#include "event.h"
++
++#include "torrent/exceptions.h"
++#include "torrent/net/fd.h"
++
++namespace torrent {
++
++void
++Event::close_file_descriptor() {
++  if (!is_open())
++    throw internal_error("Tried to close already closed file descriptor on event type " + std::string(type_name()));
++
++  fd_close(m_fileDesc);
++  m_fileDesc = -1;
++}
++
++}
+diff --git a/src/torrent/event.h b/src/torrent/event.h
+index f3549762..73f87e46 100644
+--- a/src/torrent/event.h
++++ b/src/torrent/event.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_TORRENT_EVENT_H
+ #define LIBTORRENT_TORRENT_EVENT_H
+ 
+@@ -43,26 +7,48 @@ namespace torrent {
+ 
+ class LIBTORRENT_EXPORT Event {
+ public:
+-  virtual ~Event() {}
++  Event();
++  virtual ~Event();
+ 
+-  // These are not virtual as the fd is heavily used in select based
+-  // polling, thus fast access is critical to performance.
+-  int                 file_descriptor() const { return m_fileDesc; }
++  // TODO: Disable override.
++  bool is_open() const;
+ 
+-  virtual void        event_read() = 0;
+-  virtual void        event_write() = 0;
+-  virtual void        event_error() = 0;
++  int file_descriptor() const;
+ 
+-  // Require all event types to define this function.
+-  virtual const char* type_name() const { return "default"; }
++  virtual void event_read() = 0;
++  virtual void event_write() = 0;
++  virtual void event_error() = 0;
+ 
+-  // Event closed?
++  // TODO: Require all to define their ownh typename.
++  virtual const char* type_name() const { return "default"; }
+ 
+ protected:
+-  int                 m_fileDesc;
+-  bool                m_ipv6_socket;
++  void close_file_descriptor();
++  void set_file_descriptor(int fd);
++
++  int  m_fileDesc;
++
++  // TODO: Deprecate.
++  bool m_ipv6_socket;
+ };
+ 
++inline Event::Event() : m_fileDesc(-1), m_ipv6_socket(false) {}
++inline Event::~Event() {}
++inline bool Event::is_open() const { return file_descriptor() != -1; }
++inline int  Event::file_descriptor() const { return m_fileDesc; }
++inline void Event::set_file_descriptor(int fd) { m_fileDesc = fd; }
++
++// Defined in 'src/globals.cc'.
++[[gnu::weak]] void poll_event_open(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_close(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_closed(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_insert_read(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_insert_write(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_insert_error(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_remove_read(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_remove_write(Event* event) LIBTORRENT_EXPORT;
++[[gnu::weak]] void poll_event_remove_error(Event* event) LIBTORRENT_EXPORT;
++
+ }
+ 
+ #endif
+diff --git a/src/torrent/http.h b/src/torrent/http.h
+index c68d3933..c605afa5 100644
+--- a/src/torrent/http.h
++++ b/src/torrent/http.h
+@@ -38,9 +38,9 @@
+ #define LIBTORRENT_HTTP_H
+ 
+ #include <string>
++#include <functional>
+ #include <iosfwd>
+ #include <list>
+-#include lt_tr1_functional
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/net/Makefile.am b/src/torrent/net/Makefile.am
+index 51999d19..35dd4774 100644
+--- a/src/torrent/net/Makefile.am
++++ b/src/torrent/net/Makefile.am
+@@ -1,11 +1,25 @@
+ noinst_LTLIBRARIES = libsub_torrentnet.la
+ 
+ libsub_torrentnet_la_SOURCES = \
++	address_info.cc \
++	address_info.h \
++	fd.cc \
++	fd.h \
++	socket_address.cc \
++	socket_address.h \
+ 	socket_address_key.cc \
+-	socket_address_key.h
++	socket_address_key.h \
++	socket_event.cc \
++	socket_event.h \
++	types.h
+ 
+ AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir)
+ 
+ libtorrentincludedir = $(includedir)/torrent/net
+ libtorrentinclude_HEADERS = \
+-	socket_address_key.h
++	address_info.h \
++	fd.h \
++	socket_address.h \
++	socket_address_key.h \
++	socket_event.h \
++	types.h
+diff --git a/src/torrent/net/address_info.cc b/src/torrent/net/address_info.cc
+new file mode 100644
+index 00000000..25a51ebd
+--- /dev/null
++++ b/src/torrent/net/address_info.cc
+@@ -0,0 +1,43 @@
++#include "config.h"
++
++#include "address_info.h"
++
++namespace torrent {
++
++int
++ai_get_addrinfo(const char* nodename, const char* servname, const addrinfo* hints, ai_unique_ptr& res) {
++  addrinfo* ai;
++  int err = ::getaddrinfo(nodename, servname, hints, &ai);
++
++  if (err != 0)
++    return err;
++
++  res.reset(ai);
++  return 0;
++}
++
++sa_unique_ptr
++ai_get_first_sa(const char* nodename, const char* servname, const addrinfo* hints) {
++  ai_unique_ptr aip;
++
++  if (ai_get_addrinfo(nodename, servname, hints, aip) != 0)
++    return nullptr;
++
++  return sa_copy(aip->ai_addr);
++}
++
++int
++ai_each_inet_inet6_first(const char* nodename, ai_sockaddr_func lambda) {
++  int err;
++  ai_unique_ptr ai;
++
++  // TODO: Change to a single call using hints with both inet/inet6.
++  if ((err = ai_get_addrinfo(nodename, NULL, ai_make_hint(0, PF_INET, SOCK_STREAM).get(), ai)) != 0 &&
++      (err = ai_get_addrinfo(nodename, NULL, ai_make_hint(0, PF_INET6, SOCK_STREAM).get(), ai)) != 0)
++    return err;
++
++  lambda(ai->ai_addr);
++  return 0;
++}
++
++}
+diff --git a/src/torrent/net/address_info.h b/src/torrent/net/address_info.h
+new file mode 100644
+index 00000000..c0b1c082
+--- /dev/null
++++ b/src/torrent/net/address_info.h
+@@ -0,0 +1,69 @@
++#ifndef LIBTORRENT_NET_ADDRESS_INFO_H
++#define LIBTORRENT_NET_ADDRESS_INFO_H
++
++#include <cstring>
++#include <functional>
++#include <memory>
++#include <string>
++#include <netdb.h>
++#include <torrent/common.h>
++#include <torrent/net/socket_address.h>
++
++namespace torrent {
++
++struct ai_deleter {
++  void operator()(addrinfo* ai) const { freeaddrinfo(ai); }
++};
++
++typedef std::unique_ptr<addrinfo, ai_deleter> ai_unique_ptr;
++typedef std::unique_ptr<const addrinfo, ai_deleter> c_ai_unique_ptr;
++typedef std::function<void (const sockaddr*)> ai_sockaddr_func;
++
++inline void          ai_clear(addrinfo* ai);
++inline ai_unique_ptr ai_make_hint(int flags, int family, int socktype);
++
++int ai_get_addrinfo(const char* nodename, const char* servname, const addrinfo* hints, ai_unique_ptr& res) LIBTORRENT_EXPORT;
++
++// Helper functions:
++
++// TODO: Consider servname "0".
++// TODO: ai_get_first_sa_err that returns a tuple?
++sa_unique_ptr ai_get_first_sa(const char* nodename, const char* servname = nullptr, const addrinfo* hints = nullptr) LIBTORRENT_EXPORT;
++
++int ai_each_inet_inet6_first(const char* nodename, ai_sockaddr_func lambda) LIBTORRENT_EXPORT;
++
++// Get all addrinfo's, iterate, etc.
++
++//
++// Safe conversion from unique_ptr arguments:
++//
++
++inline void aip_clear(ai_unique_ptr& aip) { return ai_clear(aip.get()); }
++
++inline int aip_get_addrinfo(const char* nodename, const char* servname, const ai_unique_ptr& hints, ai_unique_ptr& res) { return ai_get_addrinfo(nodename, servname, hints.get(), res); }
++inline int aip_get_addrinfo(const char* nodename, const char* servname, const c_ai_unique_ptr& hints, ai_unique_ptr& res) { return ai_get_addrinfo(nodename, servname, hints.get(), res); }
++
++//
++// Implementations:
++//
++
++inline void
++ai_clear(addrinfo* ai) {
++  std::memset(ai, 0, sizeof(addrinfo));  
++}
++
++inline ai_unique_ptr
++ai_make_hint(int flags, int family, int socktype) {
++  ai_unique_ptr aip(new addrinfo);
++
++  aip_clear(aip);
++  aip->ai_flags = flags;
++  aip->ai_family = family;
++  aip->ai_socktype = socktype;
++
++  return aip;
++}
++
++}
++
++#endif
+diff --git a/src/torrent/net/fd.cc b/src/torrent/net/fd.cc
+new file mode 100644
+index 00000000..07c91779
+--- /dev/null
++++ b/src/torrent/net/fd.cc
+@@ -0,0 +1,209 @@
++#include "config.h"
++
++#include "fd.h"
++
++#include <cerrno>
++#include <fcntl.h>
++#include <unistd.h>
++#include <netinet/in.h>
++#include <netinet/in_systm.h>
++#include <netinet/ip.h>
++
++#include "torrent/exceptions.h"
++#include "torrent/net/socket_address.h"
++#include "torrent/utils/log.h"
++
++#define LT_LOG(log_fmt, ...)                                    \
++  lt_log_print(LOG_CONNECTION_FD, "fd: " log_fmt, __VA_ARGS__);
++#define LT_LOG_FLAG(log_fmt)                                            \
++  lt_log_print(LOG_CONNECTION_FD, "fd: " log_fmt " (flags:0x%x)", flags);
++#define LT_LOG_FLAG_ERROR(log_fmt)                                      \
++  lt_log_print(LOG_CONNECTION_FD, "fd: " log_fmt " (flags:0x%x errno:%i message:'%s')", \
++               flags, errno, std::strerror(errno));
++#define LT_LOG_FD(log_fmt)                                      \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt, fd);
++#define LT_LOG_FD_ERROR(log_fmt)                                        \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (errno:%i message:'%s')", \
++               fd, errno, std::strerror(errno));
++#define LT_LOG_FD_SOCKADDR(log_fmt)                                   \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (address:%s)", \
++               fd, sa_pretty_str(sa).c_str());
++#define LT_LOG_FD_SOCKADDR_ERROR(log_fmt)                               \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (address:%s errno:%i message:'%s')", \
++               fd, sa_pretty_str(sa).c_str(), errno, std::strerror(errno));
++#define LT_LOG_FD_FLAG(log_fmt)                                         \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (flags:0x%x)", fd, flags);
++#define LT_LOG_FD_FLAG_ERROR(log_fmt)                                   \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (flags:0x%x errno:%i message:'%s')", \
++               fd, flags, errno, std::strerror(errno));
++#define LT_LOG_FD_VALUE(log_fmt, value)                                 \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (value:%i)", fd, (int)value);
++#define LT_LOG_FD_VALUE_ERROR(log_fmt, value)                           \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (value:%i errno:%i message:'%s')", \
++               fd, (int)value, errno, std::strerror(errno));
++
++namespace torrent {
++
++int fd__accept(int socket, sockaddr *address, socklen_t *address_len) { return ::accept(socket, address, address_len); }
++int fd__bind(int socket, const sockaddr *address, socklen_t address_len) { return ::bind(socket, address, address_len); }
++int fd__close(int fildes) { return ::close(fildes); }
++int fd__connect(int socket, const sockaddr *address, socklen_t address_len) { return ::connect(socket, address, address_len); }
++int fd__fcntl_int(int fildes, int cmd, int arg) { return ::fcntl(fildes, cmd, arg); }
++int fd__listen(int socket, int backlog) { return ::listen(socket, backlog); }
++int fd__setsockopt_int(int socket, int level, int option_name, int option_value) { return ::setsockopt(socket, level, option_name, &option_value, sizeof(int)); }
++int fd__socket(int domain, int type, int protocol) { return ::socket(domain, type, protocol); }
++
++int
++fd_open(fd_flags flags) {
++  int domain;
++  int protocol;
++
++  if (!fd_valid_flags(flags))
++    throw internal_error("torrent::fd_open failed: invalid fd_flags");
++
++  if ((flags & fd_flag_stream)) {
++    domain = SOCK_STREAM;
++    protocol = IPPROTO_TCP;
++  } else {
++    LT_LOG_FLAG("fd_open missing socket type");
++    errno = EINVAL;
++    return -1;
++  }
++
++  int fd = -1;
++
++  if (fd == -1 && !(flags & fd_flag_v4only)) {
++    LT_LOG_FLAG("fd_open opening ipv6 socket");
++    fd = fd__socket(PF_INET6, domain, protocol);
++  }
++
++  if (fd == -1 && !(flags & fd_flag_v6only)) {
++    LT_LOG_FLAG("fd_open opening ipv4 socket");
++    fd = fd__socket(PF_INET, domain, protocol);
++  }
++
++  if (fd == -1) {
++    LT_LOG_FLAG_ERROR("fd_open failed to open socket");
++    return -1;
++  }
++
++  if ((flags & fd_flag_v6only) && !fd_set_v6only(fd, true)) {
++    LT_LOG_FD_FLAG_ERROR("fd_open failed to set v6only");
++    fd_close(fd);
++    return -1;
++  }
++
++  if ((flags & fd_flag_nonblock) && !fd_set_nonblock(fd)) {
++    LT_LOG_FD_FLAG_ERROR("fd_open failed to set nonblock");
++    fd_close(fd);
++    return -1;
++  }
++
++  if ((flags & fd_flag_reuse_address) && !fd_set_reuse_address(fd, true)) {
++    LT_LOG_FD_FLAG_ERROR("fd_open failed to set reuse_address");
++    fd_close(fd);
++    return -1;
++  }
++
++  LT_LOG_FD_FLAG("fd_open succeeded");
++  return fd;
++}
++
++void
++fd_close(int fd) {
++  if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
++    throw internal_error("torrent::fd_close: tried to close stdin/out/err");
++
++  if (fd__close(fd) == -1)
++    throw internal_error("torrent::fd_close: " + std::string(strerror(errno)));
++
++  LT_LOG_FD("fd_close succeeded");
++}
++
++fd_sap_tuple
++fd_accept(int fd) {
++  sa_unique_ptr sap = sa_make_inet6();
++  socklen_t socklen = sap_length(sap);
++
++  int accept_fd = fd__accept(fd, sap.get(), &socklen);
++
++  if (accept_fd == -1) {
++    LT_LOG_FD_ERROR("fd_accept failed");
++    return fd_sap_tuple{-1, nullptr};
++  }
++
++  return fd_sap_tuple{accept_fd, std::move(sap)};
++}
++
++bool
++fd_bind(int fd, const sockaddr* sa) {
++  if (fd__bind(fd, sa, sa_length(sa)) == -1) {
++    LT_LOG_FD_SOCKADDR_ERROR("fd_bind failed");
++    return false;
++  }
++
++  LT_LOG_FD_SOCKADDR("fd_bind succeeded");
++  return true;
++}
++
++bool
++fd_connect(int fd, const sockaddr* sa) {
++  if (fd__connect(fd, sa, sa_length(sa)) == 0) {
++    LT_LOG_FD_SOCKADDR("fd_connect succeeded");
++    return true;
++  }
++
++  if (errno == EINPROGRESS) {
++    LT_LOG_FD_SOCKADDR("fd_connect succeeded and in progress");
++    return true;
++  }
++
++  LT_LOG_FD_SOCKADDR_ERROR("fd_connect failed");
++  return false;
++}
++
++bool
++fd_listen(int fd, int backlog) {
++  if (fd__listen(fd, backlog) == -1) {
++    LT_LOG_FD_VALUE_ERROR("fd_listen failed", backlog);
++    return false;
++  }
++
++  LT_LOG_FD_VALUE("fd_listen succeeded", backlog);
++  return true;
++}
++
++bool
++fd_set_nonblock(int fd) {
++  if (fd__fcntl_int(fd, F_SETFL, O_NONBLOCK) == -1) {
++    LT_LOG_FD_ERROR("fd_set_nonblock failed");
++    return false;
++  }
++
++  LT_LOG_FD("fd_set_nonblock succeeded");
++  return true;
++}
++
++bool
++fd_set_reuse_address(int fd, bool state) {
++  if (fd__setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, state) == -1) {
++    LT_LOG_FD_VALUE_ERROR("fd_set_reuse_address failed", state);
++    return false;
++  }
++
++  LT_LOG_FD_VALUE("fd_set_reuse_address succeeded", state);
++  return true;
++}
++
++bool
++fd_set_v6only(int fd, bool state) {
++  if (fd__setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, state) == -1) {
++    LT_LOG_FD_VALUE_ERROR("fd_set_v6only failed", state);
++    return false;
++  }
++
++  LT_LOG_FD_VALUE("fd_set_v6only succeeded", state);
++  return true;
++}
++
++}
+diff --git a/src/torrent/net/fd.h b/src/torrent/net/fd.h
+new file mode 100644
+index 00000000..a7094646
+--- /dev/null
++++ b/src/torrent/net/fd.h
+@@ -0,0 +1,63 @@
++#ifndef LIBTORRENT_NET_FD_H
++#define LIBTORRENT_NET_FD_H
++
++#include <string>
++#include <torrent/common.h>
++#include <torrent/net/types.h>
++
++namespace torrent {
++
++enum fd_flags : int {
++  fd_flag_stream = 0x1,
++  fd_flag_nonblock = 0x10,
++  fd_flag_reuse_address = 0x20,
++  fd_flag_v4only = 0x40,
++  fd_flag_v6only = 0x80,
++  fd_flag_all = 0xff,
++};
++
++constexpr bool fd_valid_flags(fd_flags flags);
++
++int  fd_open(fd_flags flags) LIBTORRENT_EXPORT;
++void fd_close(int fd) LIBTORRENT_EXPORT;
++
++fd_sap_tuple fd_accept(int fd) LIBTORRENT_EXPORT;
++
++bool fd_bind(int fd, const sockaddr* sa) LIBTORRENT_EXPORT;
++bool fd_connect(int fd, const sockaddr* sa) LIBTORRENT_EXPORT;
++bool fd_listen(int fd, int backlog) LIBTORRENT_EXPORT;
++
++bool fd_set_nonblock(int fd) LIBTORRENT_EXPORT;
++bool fd_set_reuse_address(int fd, bool state) LIBTORRENT_EXPORT;
++bool fd_set_v6only(int fd, bool state) LIBTORRENT_EXPORT;
++
++[[gnu::weak]] int fd__accept(int socket, sockaddr *address, socklen_t *address_len) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__bind(int socket, const sockaddr *address, socklen_t address_len) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__close(int fildes) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__connect(int socket, const sockaddr *address, socklen_t address_len) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__fcntl_int(int fildes, int cmd, int arg) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__listen(int socket, int backlog) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__setsockopt_int(int socket, int level, int option_name, int option_value) LIBTORRENT_EXPORT;
++[[gnu::weak]] int fd__socket(int domain, int type, int protocol) LIBTORRENT_EXPORT;
++
++constexpr fd_flags
++operator |(fd_flags lhs, fd_flags rhs) {
++  return static_cast<fd_flags>(static_cast<int>(lhs) | static_cast<int>(rhs));
++}
++
++inline fd_flags&
++operator |=(fd_flags& lhs, fd_flags rhs) {
++  return (lhs = lhs | rhs);
++}
++
++constexpr bool
++fd_valid_flags(fd_flags flags) {
++  return
++    (flags & fd_flag_stream) &&
++    !((flags & fd_flag_v4only) && (flags & fd_flag_v6only)) &&
++    !(flags & ~(fd_flag_all));
++}
++
++}
++
++#endif
+diff --git a/src/torrent/net/socket_address.cc b/src/torrent/net/socket_address.cc
+new file mode 100644
+index 00000000..c36ba0ae
+--- /dev/null
++++ b/src/torrent/net/socket_address.cc
+@@ -0,0 +1,559 @@
++#include "config.h"
++
++#include "socket_address.h"
++
++#include <cstring>
++#include <arpa/inet.h>
++#include <sys/un.h>
++
++// TODO: Deprecate.
++#include "rak/socket_address.h"
++
++#include "torrent/exceptions.h"
++
++namespace torrent {
++
++constexpr uint32_t
++sin6_addr32_index(const sockaddr_in6* sa, unsigned int index) {
++  return
++    (sa->sin6_addr.s6_addr[index * 4 + 0] << 24) +
++    (sa->sin6_addr.s6_addr[index * 4 + 1] << 16) +
++    (sa->sin6_addr.s6_addr[index * 4 + 2] << 8) +
++    (sa->sin6_addr.s6_addr[index * 4 + 3] << 0);
++}
++
++inline void
++sin6_addr32_set(sockaddr_in6* sa, unsigned int index, uint32_t value) {
++  sa->sin6_addr.s6_addr[index * 4 + 0] = (value >> 24);
++  sa->sin6_addr.s6_addr[index * 4 + 1] = (value >> 16);
++  sa->sin6_addr.s6_addr[index * 4 + 2] = (value >> 8);
++  sa->sin6_addr.s6_addr[index * 4 + 3] = (value >> 0);
++}
++
++inline in6_addr
++sin6_make_addr32(uint32_t addr0, uint32_t addr1, uint32_t addr2, uint32_t addr3) {
++  uint32_t addr32[4];
++  addr32[0] = htonl(addr0);
++  addr32[1] = htonl(addr1);
++  addr32[2] = htonl(addr2);
++  addr32[3] = htonl(addr3);
++
++  return *reinterpret_cast<in6_addr*>(addr32);
++}
++
++bool
++sa_is_unspec(const sockaddr* sa) {
++  return sa != NULL && sa->sa_family == AF_UNSPEC;
++}
++
++bool
++sa_is_inet(const sockaddr* sa) {
++  return sa != NULL && sa->sa_family == AF_INET;
++}
++
++bool
++sa_is_inet6(const sockaddr* sa) {
++  return sa != NULL && sa->sa_family == AF_INET6;
++}
++
++bool
++sa_is_inet_inet6(const sockaddr* sa) {
++  return sa != NULL && (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
++}
++
++bool
++sa_is_any(const sockaddr* sa) {
++  switch (sa->sa_family) {
++  case AF_INET:
++    return sin_is_any(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    if (sa_is_v4mapped(sa))
++      return sin6_addr32_index(reinterpret_cast<const sockaddr_in6*>(sa), 3) == htonl(INADDR_ANY);
++    return sin6_is_any(reinterpret_cast<const sockaddr_in6*>(sa));
++  default:
++    return true;
++  }
++}
++
++bool
++sin_is_any(const sockaddr_in* sa) {
++  return sa->sin_addr.s_addr == htonl(INADDR_ANY);
++}
++
++bool
++sin6_is_any(const sockaddr_in6* sa) {
++  return std::memcmp(&sa->sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0;
++}
++
++bool
++sa_is_broadcast(const sockaddr* sa) {
++  switch (sa->sa_family) {
++  case AF_INET:
++    return sin_is_broadcast(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    if (sa_is_v4mapped(sa))
++      return sin6_addr32_index(reinterpret_cast<const sockaddr_in6*>(sa), 3) == htonl(INADDR_BROADCAST);
++    return false;
++  default:
++    return false;
++  }
++}
++
++bool
++sin_is_broadcast(const sockaddr_in* sa) {
++  return sa->sin_addr.s_addr == htonl(INADDR_BROADCAST);
++}
++
++bool
++sa_is_v4mapped(const sockaddr* sa) {
++  return sa != NULL && sa->sa_family == AF_INET6 && sin6_is_v4mapped(reinterpret_cast<const sockaddr_in6*>(sa));
++}
++
++bool
++sin6_is_v4mapped(const sockaddr_in6* sa) {
++  return sa != NULL && IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr);
++}
++
++bool
++sa_is_port_any(const sockaddr* sa) {
++  return sa_port(sa) == 0;
++}
++
++size_t
++sa_length(const sockaddr* sa) {
++  switch(sa->sa_family) {
++  case AF_INET:
++    return sizeof(sockaddr_in);
++  case AF_INET6:
++    return sizeof(sockaddr_in6);
++  default:
++    return sizeof(sa);
++  }
++}
++
++sa_unique_ptr
++sa_make_unspec() {
++  sa_unique_ptr sa(new sockaddr);
++
++  std::memset(sa.get(), 0, sizeof(sa));
++  sa.get()->sa_family = AF_UNSPEC;
++
++  return sa;
++}
++
++sa_unique_ptr
++sa_make_inet() {
++  return sa_unique_ptr(reinterpret_cast<sockaddr*>(sin_make().release()));
++}
++
++sa_unique_ptr
++sa_make_inet6() {
++  return sa_unique_ptr(reinterpret_cast<sockaddr*>(sin6_make().release()));
++}
++
++sa_unique_ptr
++sa_make_unix(const std::string& pathname) {
++  if (!pathname.empty())
++    throw internal_error("torrent::sa_make_unix: function not implemented");
++
++  sun_unique_ptr sunp(new sockaddr_un);
++
++  std::memset(sunp.get(), 0, sizeof(sockaddr_un));
++  sunp->sun_family = AF_UNIX;
++  // TODO: verify length, copy pathname
++
++  return sa_unique_ptr(reinterpret_cast<sockaddr*>(sunp.release()));
++}
++
++sa_unique_ptr
++sa_convert(const sockaddr* sa) {
++  if (sa == NULL)
++    return sa_make_unspec();
++
++  switch(sa->sa_family) {
++  case AF_INET:
++    return sa_copy_in(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    if (sin6_is_v4mapped(reinterpret_cast<const sockaddr_in6*>(sa)))
++      return sa_from_v4mapped_in6(reinterpret_cast<const sockaddr_in6*>(sa));
++
++    return sa_copy_in6(reinterpret_cast<const sockaddr_in6*>(sa));
++  case AF_UNSPEC:
++    return sa_make_unspec();
++  default:
++    throw internal_error("torrent::sa_convert: sockaddr is not a valid family");
++  }
++}
++
++sa_unique_ptr
++sa_copy(const sockaddr* sa) {
++  if (sa == nullptr)
++    throw internal_error("torrent::sa_copy: sockaddr is a nullptr");
++
++  switch(sa->sa_family) {
++  case AF_INET:
++    return sa_copy_in(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    return sa_copy_in6(reinterpret_cast<const sockaddr_in6*>(sa));
++  case AF_UNSPEC:
++    return sa_make_unspec();
++  default:
++    throw internal_error("torrent::sa_copy: sockaddr is not a valid family");
++  }
++}
++
++sa_unique_ptr
++sa_copy_in(const sockaddr_in* sa) {
++  sa_unique_ptr result(reinterpret_cast<sockaddr*>(new sockaddr_in));
++  std::memcpy(result.get(), sa, sizeof(sockaddr_in));
++  return result;
++}
++
++sa_unique_ptr
++sa_copy_in6(const sockaddr_in6* sa) {
++  sa_unique_ptr result(reinterpret_cast<sockaddr*>(new sockaddr_in6));
++  std::memcpy(result.get(), sa, sizeof(sockaddr_in6));
++  return result;
++}
++
++sa_unique_ptr
++sa_copy_addr(const sockaddr* sa, uint16_t port) {
++  if (sa == nullptr)
++    throw internal_error("torrent::sa_copy_addr: sockaddr is a nullptr");
++
++  switch(sa->sa_family) {
++  case AF_INET:
++    return sa_copy_addr_in(reinterpret_cast<const sockaddr_in*>(sa), port);
++  case AF_INET6:
++    return sa_copy_addr_in6(reinterpret_cast<const sockaddr_in6*>(sa), port);
++  case AF_UNSPEC:
++    return sa_make_unspec();
++  default:
++    throw internal_error("torrent::sa_copy_addr: sockaddr is not a valid family");
++  }
++}
++
++sa_unique_ptr
++sa_copy_addr_in(const sockaddr_in* sa, uint16_t port) {
++  sa_unique_ptr result(reinterpret_cast<sockaddr*>(new sockaddr_in));
++  std::memset(result.get(), 0, sizeof(sockaddr_in));
++  reinterpret_cast<sockaddr_in*>(result.get())->sin_family = AF_INET;
++  reinterpret_cast<sockaddr_in*>(result.get())->sin_addr = sa->sin_addr;
++  reinterpret_cast<sockaddr_in*>(result.get())->sin_port = htons(port);
++  return result;
++}
++
++sa_unique_ptr
++sa_copy_addr_in6(const sockaddr_in6* sa, uint16_t port) {
++  sa_unique_ptr result(reinterpret_cast<sockaddr*>(new sockaddr_in6));
++  std::memset(result.get(), 0, sizeof(sockaddr_in6));
++  reinterpret_cast<sockaddr_in6*>(result.get())->sin6_family = AF_INET6;
++  std::memcpy(&reinterpret_cast<sockaddr_in6*>(result.get())->sin6_addr, &sa->sin6_addr, sizeof(in6_addr));
++  reinterpret_cast<sockaddr_in6*>(result.get())->sin6_port = htons(port);
++  return result;
++}
++
++sin_unique_ptr
++sin_copy(const sockaddr_in* sa) {
++  sin_unique_ptr result(new sockaddr_in);
++  std::memcpy(result.get(), sa, sizeof(sockaddr_in));
++  return result;
++}
++
++sin6_unique_ptr
++sin6_copy(const sockaddr_in6* sa) {
++  sin6_unique_ptr result(new sockaddr_in6);
++  std::memcpy(result.get(), sa, sizeof(sockaddr_in6));
++  return result;
++}
++
++sin_unique_ptr
++sin_make() {
++  sin_unique_ptr sa(new sockaddr_in);
++  std::memset(sa.get(), 0, sizeof(sockaddr_in));
++  sa.get()->sin_family = AF_INET;
++
++  return sa;
++}
++
++sin6_unique_ptr
++sin6_make() {
++  sin6_unique_ptr sa(new sockaddr_in6);
++  std::memset(sa.get(), 0, sizeof(sockaddr_in6));
++  sa.get()->sin6_family = AF_INET6;
++
++  return sa;
++}
++
++sa_unique_ptr
++sa_from_v4mapped(const sockaddr* sa) {
++  if (!sa_is_inet6(sa))
++    throw internal_error("torrent::sa_from_v4mapped: sockaddr is not inet6");
++
++  return sa_from_in(sin_from_v4mapped_in6(reinterpret_cast<const sockaddr_in6*>(sa)));
++}
++
++sa_unique_ptr
++sa_to_v4mapped(const sockaddr* sa) {
++  if (!sa_is_inet(sa))
++    throw internal_error("torrent::sa_to_v4mapped: sockaddr is not inet");
++
++  return sa_from_in6(sin6_to_v4mapped_in(reinterpret_cast<const sockaddr_in*>(sa)));
++}
++
++sin_unique_ptr
++sin_from_v4mapped_in6(const sockaddr_in6* sin6) {
++  if (!sin6_is_v4mapped(sin6))
++    throw internal_error("torrent::sin6_is_v4mapped: sockaddr_in6 is not v4mapped");
++
++  sin_unique_ptr result = sin_make();
++  result.get()->sin_addr.s_addr = reinterpret_cast<in_addr_t>(htonl(sin6_addr32_index(sin6, 3)));
++  result.get()->sin_port = sin6->sin6_port;
++
++  return result;
++}
++
++sin6_unique_ptr
++sin6_to_v4mapped_in(const sockaddr_in* sin) {
++  sin6_unique_ptr result = sin6_make();
++
++  result.get()->sin6_addr = sin6_make_addr32(0, 0, 0xffff, ntohl(sin->sin_addr.s_addr));
++  result.get()->sin6_port = sin->sin_port;
++
++  return result;
++}
++
++sin_unique_ptr
++sin_from_sa(sa_unique_ptr&& sap) {
++  if (!sap_is_inet(sap))
++    throw internal_error("torrent::sin_from_sa: sockaddr is nullptr or not inet");
++
++  return sin_unique_ptr(reinterpret_cast<sockaddr_in*>(sap.release()));
++}
++
++sin6_unique_ptr
++sin6_from_sa(sa_unique_ptr&& sap) {
++  if (!sap_is_inet6(sap))
++    throw internal_error("torrent::sin6_from_sa: sockaddr is nullptr or not inet6");
++
++  return sin6_unique_ptr(reinterpret_cast<sockaddr_in6*>(sap.release()));
++}
++
++c_sin_unique_ptr
++sin_from_c_sa(c_sa_unique_ptr&& sap) {
++  if (!sap_is_inet(sap))
++    throw internal_error("torrent::sin_from_c_sa: sockaddr is nullptr or not inet");
++
++  return c_sin_unique_ptr(reinterpret_cast<const sockaddr_in*>(sap.release()));
++}
++
++c_sin6_unique_ptr
++sin6_from_c_sa(sa_unique_ptr&& sap) {
++  if (!sap_is_inet6(sap))
++    throw internal_error("torrent::sin6_from_c_sa: sockaddr is nullptr or not inet6");
++
++  return c_sin6_unique_ptr(reinterpret_cast<const sockaddr_in6*>(sap.release()));
++}
++
++void
++sa_clear_inet6(sockaddr_in6* sa) {
++  std::memset(sa, 0, sizeof(sockaddr_in6));
++  sa->sin6_family = AF_INET6;
++}
++
++uint16_t
++sa_port(const sockaddr* sa) {
++  if (sa == NULL)
++    return 0;
++
++  switch(sa->sa_family) {
++  case AF_INET:
++    return ntohs(reinterpret_cast<const sockaddr_in*>(sa)->sin_port);
++  case AF_INET6:
++    return ntohs(reinterpret_cast<const sockaddr_in6*>(sa)->sin6_port);
++  default:
++    return 0;
++  }
++}
++
++void
++sa_set_port(sockaddr* sa, uint16_t port) {
++  switch(sa->sa_family) {
++  case AF_INET:
++    reinterpret_cast<sockaddr_in*>(sa)->sin_port = htons(port);
++    return;
++  case AF_INET6:
++    reinterpret_cast<sockaddr_in6*>(sa)->sin6_port = htons(port);
++    return;
++  default:
++    throw internal_error("torrent::sa_set_port: invalid family type");
++  }
++}
++
++bool
++sa_equal(const sockaddr* lhs, const sockaddr* rhs) {
++  switch(rhs->sa_family) {
++  case AF_INET:
++  case AF_INET6:
++  case AF_UNSPEC:
++    break;
++  default:
++    throw internal_error("torrent::sa_equal: rhs sockaddr is not a valid family");
++  }
++
++  switch(lhs->sa_family) {
++  case AF_INET:
++    return lhs->sa_family == rhs->sa_family &&
++      sin_equal(reinterpret_cast<const sockaddr_in*>(lhs), reinterpret_cast<const sockaddr_in*>(rhs));
++  case AF_INET6:
++    return lhs->sa_family == rhs->sa_family &&
++      sin6_equal(reinterpret_cast<const sockaddr_in6*>(lhs), reinterpret_cast<const sockaddr_in6*>(rhs));
++  case AF_UNSPEC:
++    return lhs->sa_family == rhs->sa_family;
++  default:
++    throw internal_error("torrent::sa_equal: lhs sockaddr is not a valid family");
++  }
++}
++
++bool
++sin_equal(const sockaddr_in* lhs, const sockaddr_in* rhs) {
++  return lhs->sin_port == rhs->sin_port && lhs->sin_addr.s_addr == rhs->sin_addr.s_addr;
++}
++
++bool
++sin6_equal(const sockaddr_in6* lhs, const sockaddr_in6* rhs) {
++  return lhs->sin6_port == rhs->sin6_port && std::equal(lhs->sin6_addr.s6_addr, lhs->sin6_addr.s6_addr + 16, rhs->sin6_addr.s6_addr);
++}
++
++bool
++sa_equal_addr(const sockaddr* lhs, const sockaddr* rhs) {
++  switch(rhs->sa_family) {
++  case AF_INET:
++  case AF_INET6:
++  case AF_UNSPEC:
++    break;
++  default:
++    throw internal_error("torrent::sa_equal_addr: rhs sockaddr is not a valid family");
++  }
++
++  switch(lhs->sa_family) {
++  case AF_INET:
++    return lhs->sa_family == rhs->sa_family &&
++      sin_equal_addr(reinterpret_cast<const sockaddr_in*>(lhs), reinterpret_cast<const sockaddr_in*>(rhs));
++  case AF_INET6:
++    return lhs->sa_family == rhs->sa_family &&
++      sin6_equal_addr(reinterpret_cast<const sockaddr_in6*>(lhs), reinterpret_cast<const sockaddr_in6*>(rhs));
++  case AF_UNSPEC:
++    return lhs->sa_family == rhs->sa_family;
++  default:
++    throw internal_error("torrent::sa_equal_addr: lhs sockaddr is not a valid family");
++  }
++}
++
++bool
++sin_equal_addr(const sockaddr_in* lhs, const sockaddr_in* rhs) {
++  return lhs->sin_addr.s_addr == rhs->sin_addr.s_addr;
++}
++
++bool
++sin6_equal_addr(const sockaddr_in6* lhs, const sockaddr_in6* rhs) {
++  return std::equal(lhs->sin6_addr.s6_addr, lhs->sin6_addr.s6_addr + 16, rhs->sin6_addr.s6_addr);
++}
++
++std::string
++sa_addr_str(const sockaddr* sa) {
++  if (sa == NULL)
++    return "unspec";
++
++  switch (sa->sa_family) {
++  case AF_INET:
++    return sin_addr_str(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    return sin6_addr_str(reinterpret_cast<const sockaddr_in6*>(sa));
++  case AF_UNSPEC:
++    return "unspec";
++  default:
++    return "invalid";
++  }
++}
++
++std::string
++sin_addr_str(const sockaddr_in* sa) {
++  char buffer[INET_ADDRSTRLEN];
++
++  if (inet_ntop(AF_INET, &sa->sin_addr, buffer, INET_ADDRSTRLEN) == NULL)
++    return "inet_error";
++
++  return buffer;
++}
++
++
++std::string
++sin6_addr_str(const sockaddr_in6* sa) {
++  char buffer[INET6_ADDRSTRLEN];
++
++  if (inet_ntop(AF_INET6, &sa->sin6_addr, buffer, INET6_ADDRSTRLEN) == NULL)
++    return "inet6_error";
++
++  return buffer;
++}
++
++std::string
++sa_pretty_str(const sockaddr* sa) {
++  if (sa == nullptr)
++    return "nullptr";
++
++  switch (sa->sa_family) {
++  case AF_INET:
++    return sin_pretty_str(reinterpret_cast<const sockaddr_in*>(sa));
++  case AF_INET6:
++    return sin6_pretty_str(reinterpret_cast<const sockaddr_in6*>(sa));
++  case AF_UNSPEC:
++    return "unspec";
++  default:
++    return "invalid";
++  }
++}
++
++std::string
++sin_pretty_str(const sockaddr_in* sa) {
++  auto result = sin_addr_str(sa);
++
++  if (sa->sin_port != 0)
++    result += ':' + std::to_string(ntohs(sa->sin_port));
++
++  return result;
++}
++
++std::string
++sin6_pretty_str(const sockaddr_in6* sa) {
++  auto result = "[" + sin6_addr_str(sa) + "]";
++
++  if (sa->sin6_port != 0)
++    result += ':' + std::to_string(ntohs(sa->sin6_port));
++
++  return result;
++}
++
++// Deprecated:
++
++void
++sa_inet_mapped_inet6(const sockaddr_in* sa, sockaddr_in6* mapped) {
++  uint32_t addr32[4];
++  addr32[0] = 0;
++  addr32[1] = 0;
++  addr32[2] = htonl(0xffff);
++  addr32[3] = sa->sin_addr.s_addr;
++
++  sa_clear_inet6(mapped);
++
++  mapped->sin6_addr = *reinterpret_cast<in6_addr*>(addr32);
++  mapped->sin6_port = sa->sin_port;
++}
++
++std::string
++sa_pretty_address_str(const sockaddr* sa) {
++  return sa_pretty_str(sa);
++}
++
++}
+diff --git a/src/torrent/net/socket_address.h b/src/torrent/net/socket_address.h
+new file mode 100644
+index 00000000..f64aee68
+--- /dev/null
++++ b/src/torrent/net/socket_address.h
+@@ -0,0 +1,229 @@
++#ifndef LIBTORRENT_NET_SOCKET_ADDRESS_H
++#define LIBTORRENT_NET_SOCKET_ADDRESS_H
++
++#include <memory>
++#include <string>
++#include <netinet/in.h>
++#include <sys/socket.h>
++#include <torrent/common.h>
++#include <torrent/net/types.h>
++
++namespace torrent {
++
++bool sa_is_unspec(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sa_is_inet(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sa_is_inet6(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sa_is_inet_inet6(const sockaddr* sa) LIBTORRENT_EXPORT;
++
++bool sa_is_any(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sin_is_any(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++bool sin6_is_any(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++bool sa_is_broadcast(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sin_is_broadcast(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++
++bool sa_is_v4mapped(const sockaddr* sa) LIBTORRENT_EXPORT;
++bool sin6_is_v4mapped(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++bool sa_is_port_any(const sockaddr* sa) LIBTORRENT_EXPORT;
++
++size_t sa_length(const sockaddr* sa) LIBTORRENT_EXPORT;
++
++sa_unique_ptr   sa_make_unspec() LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_make_inet() LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_make_inet6() LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_make_unix(const std::string& pathname) LIBTORRENT_EXPORT;
++
++sa_unique_ptr   sa_convert(const sockaddr* sa) LIBTORRENT_EXPORT;
++
++sa_unique_ptr   sa_copy(const sockaddr* sa) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_copy_in(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_copy_in6(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_copy_addr(const sockaddr* sa, uint16_t port = 0) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_copy_addr_in(const sockaddr_in* sa, uint16_t port = 0) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_copy_addr_in6(const sockaddr_in6* sa, uint16_t port = 0) LIBTORRENT_EXPORT;
++sin_unique_ptr  sin_copy(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++sin6_unique_ptr sin6_copy(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++sin_unique_ptr  sin_make() LIBTORRENT_EXPORT;
++sin6_unique_ptr sin6_make() LIBTORRENT_EXPORT;
++
++sa_unique_ptr   sa_from_v4mapped(const sockaddr* sa) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_to_v4mapped(const sockaddr* sa) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_from_v4mapped_in6(const sockaddr_in6* sin6) LIBTORRENT_EXPORT;
++sa_unique_ptr   sa_to_v4mapped_in(const sockaddr_in* sin) LIBTORRENT_EXPORT;
++sin_unique_ptr  sin_from_v4mapped_in6(const sockaddr_in6* sin6) LIBTORRENT_EXPORT;
++sin6_unique_ptr sin6_to_v4mapped_in(const sockaddr_in* sin) LIBTORRENT_EXPORT;
++
++sa_unique_ptr     sa_from_in(sin_unique_ptr&& sinp) LIBTORRENT_EXPORT;
++c_sa_unique_ptr   sa_from_in(c_sin_unique_ptr&& sinp) LIBTORRENT_EXPORT;
++sa_unique_ptr     sa_from_in6(sin6_unique_ptr&& sin6p) LIBTORRENT_EXPORT;
++c_sa_unique_ptr   sa_from_in6(c_sin6_unique_ptr&& sin6p) LIBTORRENT_EXPORT;
++sin_unique_ptr    sin_from_sa(sa_unique_ptr&& sap) LIBTORRENT_EXPORT;
++sin6_unique_ptr   sin6_from_sa(sa_unique_ptr&& sap) LIBTORRENT_EXPORT;
++c_sin_unique_ptr  sin_from_c_sa(c_sa_unique_ptr&& sap) LIBTORRENT_EXPORT;
++c_sin6_unique_ptr sin6_from_c_sa(c_sa_unique_ptr&& sap) LIBTORRENT_EXPORT;
++
++void        sa_clear_inet6(sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++uint16_t    sa_port(const sockaddr* sa) LIBTORRENT_EXPORT;
++void        sa_set_port(sockaddr* sa, uint16_t port) LIBTORRENT_EXPORT;
++
++bool        sa_equal(const sockaddr* lhs, const sockaddr* rhs) LIBTORRENT_EXPORT;
++bool        sin_equal(const sockaddr_in* lhs, const sockaddr_in* rhs) LIBTORRENT_EXPORT;
++bool        sin6_equal(const sockaddr_in6* lhs, const sockaddr_in6* rhs) LIBTORRENT_EXPORT;
++
++bool        sa_equal_addr(const sockaddr* lhs, const sockaddr* rhs) LIBTORRENT_EXPORT;
++bool        sin_equal_addr(const sockaddr_in* lhs, const sockaddr_in* rhs) LIBTORRENT_EXPORT;
++bool        sin6_equal_addr(const sockaddr_in6* lhs, const sockaddr_in6* rhs) LIBTORRENT_EXPORT;
++
++std::string sa_addr_str(const sockaddr* sa) LIBTORRENT_EXPORT;
++std::string sin_addr_str(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++std::string sin6_addr_str(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++std::string sa_pretty_str(const sockaddr* sa) LIBTORRENT_EXPORT;
++std::string sin_pretty_str(const sockaddr_in* sa) LIBTORRENT_EXPORT;
++std::string sin6_pretty_str(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
++
++// Rename/replace:
++void sa_inet_mapped_inet6(const sockaddr_in* sa, sockaddr_in6* mapped) LIBTORRENT_EXPORT;
++
++std::string sa_pretty_address_str(const sockaddr* sa) LIBTORRENT_EXPORT;
++
++//
++// Tuples:
++//
++
++bool fd_sap_equal(const fd_sap_tuple& lhs, const fd_sap_tuple& rhs) LIBTORRENT_EXPORT;
++
++//
++// Safe conversion from unique_ptr arguments:
++//
++
++inline bool sap_is_unspec(const sa_unique_ptr& sap) { return sa_is_unspec(sap.get()); }
++inline bool sap_is_unspec(const c_sa_unique_ptr& sap) { return sa_is_unspec(sap.get()); }
++inline bool sap_is_inet(const c_sa_unique_ptr& sap) { return sa_is_inet(sap.get()); }
++inline bool sap_is_inet(const sa_unique_ptr& sap) { return sa_is_inet(sap.get()); }
++inline bool sap_is_inet6(const sa_unique_ptr& sap) { return sa_is_inet6(sap.get()); }
++inline bool sap_is_inet6(const c_sa_unique_ptr& sap) { return sa_is_inet6(sap.get()); }
++inline bool sap_is_inet_inet6(const sa_unique_ptr& sap) { return sa_is_inet_inet6(sap.get()); }
++inline bool sap_is_inet_inet6(const c_sa_unique_ptr& sap) { return sa_is_inet_inet6(sap.get()); }
++
++inline bool sap_is_any(const sa_unique_ptr& sap) { return sa_is_any(sap.get()); }
++inline bool sap_is_any(const c_sa_unique_ptr& sap) { return sa_is_any(sap.get()); }
++inline bool sinp_is_any(const sin_unique_ptr& sinp) { return sin_is_any(sinp.get()); }
++inline bool sinp_is_any(const c_sin_unique_ptr& sinp) { return sin_is_any(sinp.get()); }
++inline bool sinp6_is_any(const sin6_unique_ptr& sin6p) { return sin6_is_any(sin6p.get()); }
++inline bool sinp6_is_any(const c_sin6_unique_ptr& sin6p) { return sin6_is_any(sin6p.get()); }
++
++inline bool sap_is_broadcast(const sa_unique_ptr& sap) { return sa_is_broadcast(sap.get()); }
++inline bool sap_is_broadcast(const c_sa_unique_ptr& sap) { return sa_is_broadcast(sap.get()); }
++inline bool sinp_is_broadcast(const sin_unique_ptr& sap) { return sin_is_broadcast(sap.get()); }
++inline bool sinp_is_broadcast(const c_sin_unique_ptr& sap) { return sin_is_broadcast(sap.get()); }
++
++inline bool sap_is_v4mapped(const sa_unique_ptr& sap) { return sa_is_v4mapped(sap.get()); }
++inline bool sap_is_v4mapped(const c_sa_unique_ptr& sap) { return sa_is_v4mapped(sap.get()); }
++inline bool sinp6_is_v4mapped(const sin6_unique_ptr& sin6p) { return sin6_is_v4mapped(sin6p.get()); }
++inline bool sinp6_is_v4mapped(const c_sin6_unique_ptr& sin6p) { return sin6_is_v4mapped(sin6p.get()); }
++
++inline bool sap_is_port_any(const sa_unique_ptr& sap) { return sa_is_port_any(sap.get()); }
++inline bool sap_is_port_any(const c_sa_unique_ptr& sap) { return sa_is_port_any(sap.get()); }
++
++inline size_t sap_length(const sa_unique_ptr& sap) { return sa_length(sap.get()); }
++inline size_t sap_length(const c_sa_unique_ptr& sap) { return sa_length(sap.get()); }
++
++inline sa_unique_ptr sap_copy(const sa_unique_ptr& sap) { return sa_copy(sap.get()); }
++inline sa_unique_ptr sap_copy(const c_sa_unique_ptr& sap) { return sa_copy(sap.get()); }
++inline sa_unique_ptr sap_copy_addr(const sa_unique_ptr& sap, uint16_t port = 0) { return sa_copy_addr(sap.get(), port); }
++inline sa_unique_ptr sap_copy_addr(const c_sa_unique_ptr& sap, uint16_t port = 0) { return sa_copy_addr(sap.get(), port); }
++inline sa_unique_ptr sap_copy_in(const sin_unique_ptr& sinp) { return sa_copy_in(sinp.get()); }
++inline sa_unique_ptr sap_copy_in(const c_sin_unique_ptr& sinp) { return sa_copy_in(sinp.get()); }
++inline sa_unique_ptr sap_copy_in6(const sin6_unique_ptr& sin6p) { return sa_copy_in6(sin6p.get()); }
++inline sa_unique_ptr sap_copy_in6(const c_sin6_unique_ptr& sin6p) { return sa_copy_in6(sin6p.get()); }
++
++inline sa_unique_ptr   sap_from_v4mapped(const sa_unique_ptr& sap) { return sa_from_v4mapped(sap.get()); }
++inline sa_unique_ptr   sap_from_v4mapped(const c_sa_unique_ptr& sap) { return sa_from_v4mapped(sap.get()); }
++inline sa_unique_ptr   sap_to_v4mapped(const sa_unique_ptr& sap) { return sa_to_v4mapped(sap.get()); }
++inline sa_unique_ptr   sap_to_v4mapped(const c_sa_unique_ptr& sap) { return sa_to_v4mapped(sap.get()); }
++inline sin_unique_ptr  sinp_from_v4mapped_in6(const sin6_unique_ptr& sin6p) { return sin_from_v4mapped_in6(sin6p.get()); }
++inline sin_unique_ptr  sinp_from_v4mapped_in6(const c_sin6_unique_ptr& sin6p) { return sin_from_v4mapped_in6(sin6p.get()); }
++inline sin6_unique_ptr sin6p_to_v4mapped_in(const sin_unique_ptr& sinp) { return sin6_to_v4mapped_in(sinp.get()); }
++inline sin6_unique_ptr sin6p_to_v4mapped_in(const c_sin_unique_ptr& sinp) { return sin6_to_v4mapped_in(sinp.get()); }
++
++inline uint16_t sap_port(const sa_unique_ptr& sap) { return sa_port(sap.get()); }
++inline uint16_t sap_port(const c_sa_unique_ptr& sap) { return sa_port(sap.get()); }
++inline void sap_set_port(const sa_unique_ptr& sap, uint16_t port) { sa_set_port(sap.get(), port); }
++
++inline bool sap_equal(const sa_unique_ptr& lhs, const sa_unique_ptr& rhs) { return sa_equal(lhs.get(), rhs.get()); }
++inline bool sap_equal(const sa_unique_ptr& lhs, const c_sa_unique_ptr& rhs) { return sa_equal(lhs.get(), rhs.get()); }
++inline bool sap_equal(const c_sa_unique_ptr& lhs, const sa_unique_ptr& rhs) { return sa_equal(lhs.get(), rhs.get()); }
++inline bool sap_equal(const c_sa_unique_ptr& lhs, const c_sa_unique_ptr& rhs) { return sa_equal(lhs.get(), rhs.get()); }
++inline bool sinp_equal(const sin_unique_ptr& lhs, const sin_unique_ptr& rhs) { return sin_equal(lhs.get(), rhs.get()); }
++inline bool sinp_equal(const sin_unique_ptr& lhs, const c_sin_unique_ptr& rhs) { return sin_equal(lhs.get(), rhs.get()); }
++inline bool sinp_equal(const c_sin_unique_ptr& lhs, const sin_unique_ptr& rhs) { return sin_equal(lhs.get(), rhs.get()); }
++inline bool sinp_equal(const c_sin_unique_ptr& lhs, const c_sin_unique_ptr& rhs) { return sin_equal(lhs.get(), rhs.get()); }
++inline bool sin6p_equal(const sin6_unique_ptr& lhs, const sin6_unique_ptr& rhs) { return sin6_equal(lhs.get(), rhs.get()); }
++inline bool sin6p_equal(const sin6_unique_ptr& lhs, const c_sin6_unique_ptr& rhs) { return sin6_equal(lhs.get(), rhs.get()); }
++inline bool sin6p_equal(const c_sin6_unique_ptr& lhs, const sin6_unique_ptr& rhs) { return sin6_equal(lhs.get(), rhs.get()); }
++inline bool sin6p_equal(const c_sin6_unique_ptr& lhs, const c_sin6_unique_ptr& rhs) { return sin6_equal(lhs.get(), rhs.get()); }
++
++inline bool sap_equal_addr(const sa_unique_ptr& lhs, const sa_unique_ptr& rhs) { return sa_equal_addr(lhs.get(), rhs.get()); }
++inline bool sap_equal_addr(const sa_unique_ptr& lhs, const c_sa_unique_ptr& rhs) { return sa_equal_addr(lhs.get(), rhs.get()); }
++inline bool sap_equal_addr(const c_sa_unique_ptr& lhs, const sa_unique_ptr& rhs) { return sa_equal_addr(lhs.get(), rhs.get()); }
++inline bool sap_equal_addr(const c_sa_unique_ptr& lhs, const c_sa_unique_ptr& rhs) { return sa_equal_addr(lhs.get(), rhs.get()); }
++inline bool sinp_equal_addr(const sin_unique_ptr& lhs, const sin_unique_ptr& rhs) { return sin_equal_addr(lhs.get(), rhs.get()); }
++inline bool sinp_equal_addr(const sin_unique_ptr& lhs, const c_sin_unique_ptr& rhs) { return sin_equal_addr(lhs.get(), rhs.get()); }
++inline bool sinp_equal_addr(const c_sin_unique_ptr& lhs, const sin_unique_ptr& rhs) { return sin_equal_addr(lhs.get(), rhs.get()); }
++inline bool sinp_equal_addr(const c_sin_unique_ptr& lhs, const c_sin_unique_ptr& rhs) { return sin_equal_addr(lhs.get(), rhs.get()); }
++inline bool sin6p_equal_addr(const sin6_unique_ptr& lhs, const sin6_unique_ptr& rhs) { return sin6_equal_addr(lhs.get(), rhs.get()); }
++inline bool sin6p_equal_addr(const sin6_unique_ptr& lhs, const c_sin6_unique_ptr& rhs) { return sin6_equal_addr(lhs.get(), rhs.get()); }
++inline bool sin6p_equal_addr(const c_sin6_unique_ptr& lhs, const sin6_unique_ptr& rhs) { return sin6_equal_addr(lhs.get(), rhs.get()); }
++inline bool sin6p_equal_addr(const c_sin6_unique_ptr& lhs, const c_sin6_unique_ptr& rhs) { return sin6_equal_addr(lhs.get(), rhs.get()); }
++
++inline std::string sap_addr_str(const sa_unique_ptr& sap) { return sa_addr_str(sap.get()); }
++inline std::string sap_addr_str(const c_sa_unique_ptr& sap) { return sa_addr_str(sap.get()); }
++inline std::string sap_pretty_str(const sa_unique_ptr& sap) { return sa_pretty_str(sap.get()); }
++inline std::string sap_pretty_str(const c_sa_unique_ptr& sap) { return sa_pretty_str(sap.get()); }
++
++//
++// Implementations:
++//
++
++inline sa_unique_ptr
++sa_from_v4mapped_in6(const sockaddr_in6* sin6) {
++  return sa_from_in(sin_from_v4mapped_in6(sin6));
++}
++
++inline sa_unique_ptr
++sa_to_v4mapped_in(const sockaddr_in* sin) {
++  return sa_from_in6(sin6_to_v4mapped_in(sin));
++}
++
++inline sa_unique_ptr
++sa_from_in(sin_unique_ptr&& sinp) {
++  return sa_unique_ptr(reinterpret_cast<sockaddr*>(sinp.release()));
++}
++
++inline c_sa_unique_ptr
++sa_from_in(c_sin_unique_ptr&& sinp) {
++  return c_sa_unique_ptr(reinterpret_cast<const sockaddr*>(sinp.release()));
++}
++
++inline sa_unique_ptr
++sa_from_in6(sin6_unique_ptr&& sin6p) {
++  return sa_unique_ptr(reinterpret_cast<sockaddr*>(sin6p.release()));
++}
++
++inline c_sa_unique_ptr
++sa_from_in6(c_sin6_unique_ptr&& sin6p) {
++  return c_sa_unique_ptr(reinterpret_cast<const sockaddr*>(sin6p.release()));
++}
++
++inline bool
++fd_sap_equal(const fd_sap_tuple& lhs, const fd_sap_tuple& rhs) {
++  return std::get<0>(lhs) == std::get<0>(rhs) && sap_equal(std::get<1>(lhs), std::get<1>(rhs));
++}
++
++}
++
++#endif
+diff --git a/src/torrent/net/socket_address_key.h b/src/torrent/net/socket_address_key.h
+index 9d6e0c49..0fd0feb3 100644
+--- a/src/torrent/net/socket_address_key.h
++++ b/src/torrent/net/socket_address_key.h
+@@ -5,7 +5,7 @@
+ #define LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H
+ 
+ #include <cstring>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <netinet/in.h>
+ 
+ // Unique key for the socket address, excluding port numbers, etc.
+diff --git a/src/torrent/net/socket_event.cc b/src/torrent/net/socket_event.cc
+new file mode 100644
+index 00000000..e6805290
+--- /dev/null
++++ b/src/torrent/net/socket_event.cc
+@@ -0,0 +1,29 @@
++#include "config.h"
++
++#include "socket_event.h"
++
++#include "torrent/exceptions.h"
++
++namespace torrent {
++
++socket_event::~socket_event() {
++  if (is_open())
++    throw internal_error("Called socket_event::~socket_event while still open on type " + std::string(type_name()));
++}
++
++void
++socket_event::event_read() {
++  throw internal_error("Called unsupported socket_event::event_read on type " + std::string(type_name()));
++}
++
++void
++socket_event::event_write() {
++  throw internal_error("Called unsupported socket_event::event_write on type " + std::string(type_name()));
++}
++
++void
++socket_event::event_error() {
++  throw internal_error("Called unsupported socket_event::event_error on type " + std::string(type_name()));
++}
++
++}
+diff --git a/src/torrent/net/socket_event.h b/src/torrent/net/socket_event.h
+new file mode 100644
+index 00000000..d9904bd6
+--- /dev/null
++++ b/src/torrent/net/socket_event.h
+@@ -0,0 +1,31 @@
++#ifndef LIBTORRENT_SOCKET_EVENT_H
++#define LIBTORRENT_SOCKET_EVENT_H
++
++#include <cinttypes>
++
++#include "torrent/event.h"
++#include "torrent/net/socket_address.h"
++
++namespace torrent {
++
++class LIBTORRENT_EXPORT socket_event : public Event {
++public:
++  ~socket_event() override;
++
++  const sockaddr* socket_address() const;
++  uint16_t        socket_address_port() const;
++
++  void event_read() override;
++  void event_write() override;
++  void event_error() override;
++
++protected:
++  sa_unique_ptr m_socket_address;
++};
++
++inline const sockaddr* socket_event::socket_address() const { return m_socket_address.get(); }
++inline uint16_t        socket_event::socket_address_port() const { return sap_port(m_socket_address); }
++
++}
++
++#endif
+diff --git a/src/torrent/net/types.h b/src/torrent/net/types.h
+new file mode 100644
+index 00000000..016e8b85
+--- /dev/null
++++ b/src/torrent/net/types.h
+@@ -0,0 +1,33 @@
++#ifndef LIBTORRENT_NET_TYPES_H
++#define LIBTORRENT_NET_TYPES_H
++
++#include <memory>
++#include <tuple>
++#include <sys/socket.h>
++
++struct sockaddr_in;
++struct sockaddr_in6;
++struct sockaddr_un;
++
++namespace torrent {
++
++typedef std::unique_ptr<sockaddr>     sa_unique_ptr;
++typedef std::unique_ptr<sockaddr_in>  sin_unique_ptr;
++typedef std::unique_ptr<sockaddr_in6> sin6_unique_ptr;
++typedef std::unique_ptr<sockaddr_un>  sun_unique_ptr;
++
++typedef std::unique_ptr<const sockaddr>     c_sa_unique_ptr;
++typedef std::unique_ptr<const sockaddr_in>  c_sin_unique_ptr;
++typedef std::unique_ptr<const sockaddr_in6> c_sin6_unique_ptr;
++typedef std::unique_ptr<const sockaddr_un>  c_sun_unique_ptr;
++
++typedef std::tuple<int, std::unique_ptr<sockaddr>> fd_sap_tuple;
++
++struct listen_result_type {
++  int fd;
++  sa_unique_ptr address;
++};
++
++}
++
++#endif
+diff --git a/src/torrent/object.h b/src/torrent/object.h
+index 3325a434..3f9fe7e4 100644
+--- a/src/torrent/object.h
++++ b/src/torrent/object.h
+@@ -37,8 +37,9 @@
+ #ifndef LIBTORRENT_OBJECT_H
+ #define LIBTORRENT_OBJECT_H
+ 
+-#include <string>
++#include <limits>
+ #include <map>
++#include <string>
+ #include <vector>
+ #include <torrent/common.h>
+ #include <torrent/exceptions.h>
+@@ -162,6 +163,7 @@ public:
+   string_type&        as_string()                             { check_throw(TYPE_STRING); return _string(); }
+   const string_type&  as_string() const                       { check_throw(TYPE_STRING); return _string(); }
+   const string_type&  as_string_c() const                     { check_throw(TYPE_STRING); return _string(); }
++  const char*         as_c_str() const                        { check_throw(TYPE_STRING); return _string().c_str(); }
+   list_type&          as_list()                               { check_throw(TYPE_LIST); return _list(); }
+   const list_type&    as_list() const                         { check_throw(TYPE_LIST); return _list(); }
+   map_type&           as_map()                                { check_throw(TYPE_MAP); return _map(); }
+@@ -179,6 +181,8 @@ public:
+   raw_map&            as_raw_map()                            { check_throw(TYPE_RAW_MAP); return _raw_map(); }
+   const raw_map&      as_raw_map() const                      { check_throw(TYPE_RAW_MAP); return _raw_map(); }
+ 
++  template <typename T> T as_value_type(const char* err_msg) const { check_value_throw<T>(err_msg); return _value(); }
++
+   bool                has_key(const key_type& k) const        { check_throw(TYPE_MAP); return _map().find(k) != _map().end(); }
+   bool                has_key_value(const key_type& k) const  { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_VALUE); }
+   bool                has_key_string(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_STRING); }
+@@ -246,6 +250,8 @@ public:
+   inline bool         check(map_type::const_iterator itr, type_type t) const { return itr != _map().end() && itr->second.type() == t; }
+   inline void         check_throw(type_type t) const                         { if (t != type()) throw bencode_error("Wrong object type."); }
+ 
++  template <typename T> void check_value_throw(const char* err_msg) const;
++
+   uint32_t            m_flags;
+ 
+ #ifndef HAVE_STDCXX_0X
+@@ -484,6 +490,19 @@ object_equal(const Object& left, const Object& right) {
+   }
+ }
+ 
++template <typename T>
++inline void
++Object::check_value_throw(const char* err_msg) const {
++  if (!std::numeric_limits<T>::is_integer)
++    throw internal_error("Tried to check value with non-integer type.");
++
++  if (!is_value())
++    throw bencode_error(err_msg);
++
++  if (!(_value() >= std::numeric_limits<T>::min() && _value() <= std::numeric_limits<T>::max()))
++    throw bencode_error(err_msg);
++}
++
+ }
+ 
+ #endif
+diff --git a/src/torrent/peer/client_list.cc b/src/torrent/peer/client_list.cc
+index c857f62d..9c18aa50 100644
+--- a/src/torrent/peer/client_list.cc
++++ b/src/torrent/peer/client_list.cc
+@@ -37,8 +37,8 @@
+ #include "config.h"
+ 
+ #include <algorithm>
++#include <functional>
+ #include <rak/string_manip.h>
+-#include lt_tr1_functional
+ 
+ #include "client_list.h"
+ #include "exceptions.h"
+diff --git a/src/torrent/peer/connection_list.h b/src/torrent/peer/connection_list.h
+index ec26835f..eb058784 100644
+--- a/src/torrent/peer/connection_list.h
++++ b/src/torrent/peer/connection_list.h
+@@ -37,9 +37,10 @@
+ #ifndef LIBTORRENT_PEER_CONNECTION_LIST_H
+ #define LIBTORRENT_PEER_CONNECTION_LIST_H
+ 
++#include <functional>
+ #include <list>
+ #include <vector>
+-#include lt_tr1_functional
++
+ #include <torrent/common.h>
+ #include <torrent/hash_string.h>
+ 
+diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc
+index aa60939a..080a7f13 100644
+--- a/src/torrent/peer/peer_list.cc
++++ b/src/torrent/peer/peer_list.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include <algorithm>
+ #include <functional>
+ #include <rak/functional.h>
+@@ -56,6 +54,8 @@
+ 
+ #define LT_LOG_EVENTS(log_fmt, ...)                                     \
+   lt_log_print_info(LOG_PEER_LIST_EVENTS, m_info, "peer_list", log_fmt, __VA_ARGS__);
++#define LT_LOG_ADDRESS(log_fmt, ...)                                    \
++  lt_log_print_info(LOG_PEER_LIST_ADDRESS, m_info, "peer_list", log_fmt, __VA_ARGS__);
+ #define LT_LOG_SA_FMT "'%s:%" PRIu16 "'"
+ 
+ namespace torrent {
+@@ -196,6 +196,7 @@ PeerList::insert_available(const void* al) {
+   for (; itr != last; itr++) {
+     if (!socket_address_key::is_comparable_sockaddr(itr->c_sockaddr()) || itr->port() == 0) {
+       invalid++;
++      LT_LOG_ADDRESS("skipped invalid address " LT_LOG_SA_FMT, itr->address_str().c_str(), itr->port());
+       continue;
+     }
+ 
+@@ -242,6 +243,8 @@ PeerList::insert_available(const void* al) {
+ 
+     inserted++;
+     m_available_list->push_back(&*itr);
++
++    LT_LOG_ADDRESS("added available address " LT_LOG_SA_FMT, itr->address_str().c_str(), itr->port());
+   }
+ 
+   LT_LOG_EVENTS("inserted peers"
+diff --git a/src/torrent/poll.h b/src/torrent/poll.h
+index b12c8ec2..15a73897 100644
+--- a/src/torrent/poll.h
++++ b/src/torrent/poll.h
+@@ -37,8 +37,7 @@
+ #ifndef LIBTORRENT_TORRENT_POLL_H
+ #define LIBTORRENT_TORRENT_POLL_H
+ 
+-#include lt_tr1_functional
+-
++#include <functional>
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/torrent.cc b/src/torrent/torrent.cc
+index 339c2c4f..fb70d247 100644
+--- a/src/torrent/torrent.cc
++++ b/src/torrent/torrent.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"
+ 
+ #include <rak/address_info.h>
+@@ -139,8 +103,8 @@ main_thread() {
+ 
+ ChunkManager*      chunk_manager() { return manager->chunk_manager(); }
+ ClientList*        client_list() { return manager->client_list(); }
+-FileManager*       file_manager() { return manager->file_manager(); }
+ ConnectionManager* connection_manager() { return manager->connection_manager(); }
++FileManager*       file_manager() { return manager->file_manager(); }
+ DhtManager*        dht_manager() { return manager->dht_manager(); }
+ ResourceManager*   resource_manager() { return manager->resource_manager(); }
+ 
+@@ -189,8 +153,10 @@ download_add(Object* object) {
+     download->main()->set_metadata_size(metadata_size);
+   }
+ 
++  std::string local_id = PEER_NAME + rak::generate_random<std::string>(20 - std::string(PEER_NAME).size());
++
+   download->set_hash_queue(manager->hash_queue());
+-  download->initialize(infoHash, PEER_NAME + rak::generate_random<std::string>(20 - std::string(PEER_NAME).size()));
++  download->initialize(infoHash, local_id);
+ 
+   // Add trackers, etc, after setting the info hash so that log
+   // entries look sane.
+diff --git a/src/torrent/torrent.h b/src/torrent/torrent.h
+index 7bcf88fe..0cdfdaa7 100644
+--- a/src/torrent/torrent.h
++++ b/src/torrent/torrent.h
+@@ -44,6 +44,11 @@
+ 
+ namespace torrent {
+ 
++class FileManager;
++class ResourceManager;
++
++class thread_base;
++
+ // Make sure you seed srandom and srand48 if available.
+ void                initialize() LIBTORRENT_EXPORT;
+ 
+@@ -53,16 +58,12 @@ void                cleanup() LIBTORRENT_EXPORT;
+ 
+ bool                is_inactive() LIBTORRENT_EXPORT;
+ 
+-class FileManager;
+-class ResourceManager;
+-class thread_base;
+-
+ thread_base*        main_thread() LIBTORRENT_EXPORT;
+ 
+ ChunkManager*       chunk_manager() LIBTORRENT_EXPORT;
+ ClientList*         client_list() LIBTORRENT_EXPORT;
+-FileManager*        file_manager() LIBTORRENT_EXPORT;
+ ConnectionManager*  connection_manager() LIBTORRENT_EXPORT;
++FileManager*        file_manager() LIBTORRENT_EXPORT;
+ DhtManager*         dht_manager() LIBTORRENT_EXPORT;
+ ResourceManager*    resource_manager() LIBTORRENT_EXPORT;
+ 
+diff --git a/src/torrent/tracker.h b/src/torrent/tracker.h
+index a528ef6a..bd7546a9 100644
+--- a/src/torrent/tracker.h
++++ b/src/torrent/tracker.h
+@@ -2,7 +2,7 @@
+ #define LIBTORRENT_TRACKER_H
+ 
+ #include <string>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/tracker_controller.h b/src/torrent/tracker_controller.h
+index 70d1b43f..9452be0f 100644
+--- a/src/torrent/tracker_controller.h
++++ b/src/torrent/tracker_controller.h
+@@ -37,8 +37,9 @@
+ #ifndef LIBTORRENT_TRACKER_CONTROLLER_H
+ #define LIBTORRENT_TRACKER_CONTROLLER_H
+ 
++#include <functional>
+ #include <string>
+-#include lt_tr1_functional
++
+ #include <torrent/common.h>
+ #include <torrent/tracker.h>
+ 
+diff --git a/src/torrent/tracker_list.h b/src/torrent/tracker_list.h
+index c6817b3a..bb06f8af 100644
+--- a/src/torrent/tracker_list.h
++++ b/src/torrent/tracker_list.h
+@@ -38,10 +38,10 @@
+ #define LIBTORRENT_TRACKER_LIST_H
+ 
+ #include <algorithm>
++#include <functional>
+ #include <string>
+ #include <vector>
+ #include <torrent/common.h>
+-#include lt_tr1_functional
+ 
+ namespace torrent {
+ 
+diff --git a/src/torrent/utils/Makefile.am b/src/torrent/utils/Makefile.am
+index 51c9a026..a48786c6 100644
+--- a/src/torrent/utils/Makefile.am
++++ b/src/torrent/utils/Makefile.am
+@@ -8,10 +8,10 @@ libsub_torrentutils_la_SOURCES = \
+ 	log.h \
+ 	log_buffer.cc \
+ 	log_buffer.h \
+-	net.cc \
+-	net.h \
+ 	option_strings.cc \
+ 	option_strings.h \
++	random.cc \
++	random.h \
+ 	ranges.h \
+ 	resume.cc \
+ 	resume.h \
+@@ -32,7 +32,6 @@ libtorrentinclude_HEADERS = \
+ 	extents.h \
+ 	log.h \
+ 	log_buffer.h \
+-	net.h \
+ 	option_strings.h \
+ 	ranges.h \
+ 	resume.h \
+diff --git a/src/torrent/utils/directory_events.h b/src/torrent/utils/directory_events.h
+index 30fa0508..fd9246c5 100644
+--- a/src/torrent/utils/directory_events.h
++++ b/src/torrent/utils/directory_events.h
+@@ -37,9 +37,10 @@
+ #ifndef LIBTORRENT_DIRECTORY_EVENTS_H
+ #define LIBTORRENT_DIRECTORY_EVENTS_H
+ 
++#include <functional>
+ #include <string>
+ #include <vector>
+-#include lt_tr1_functional
++
+ #include <torrent/event.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index 6c605474..b855a2c6 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -1,45 +1,6 @@
+-// 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
+-
+ #include "log.h"
+-#include "log_buffer.h"
+ 
+ #include "globals.h"
+ #include "torrent/exceptions.h"
+@@ -54,8 +15,6 @@
+ #include <fstream>
+ #include <functional>
+ #include <memory>
+-#include lt_tr1_functional
+-#include lt_tr1_memory
+ 
+ namespace torrent {
+ 
+@@ -232,7 +191,6 @@ log_initialize() {
+ 
+   LOG_CASCADE(LOG_CRITICAL);
+ 
+-  LOG_CASCADE(LOG_CONNECTION_CRITICAL);
+   LOG_CASCADE(LOG_PEER_CRITICAL);
+   LOG_CASCADE(LOG_SOCKET_CRITICAL);
+   LOG_CASCADE(LOG_STORAGE_CRITICAL);
+@@ -240,7 +198,6 @@ log_initialize() {
+   LOG_CASCADE(LOG_TRACKER_CRITICAL);
+   LOG_CASCADE(LOG_TORRENT_CRITICAL);
+ 
+-  LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_CONNECTION_CRITICAL);
+   LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_PEER_CRITICAL);
+   LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_SOCKET_CRITICAL);
+   LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_STORAGE_CRITICAL);
+@@ -248,6 +205,12 @@ log_initialize() {
+   LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_TRACKER_CRITICAL);
+   LOG_CHILDREN_CASCADE(LOG_CRITICAL, LOG_TORRENT_CRITICAL);
+ 
++  LOG_LINK(LOG_CONNECTION, LOG_CONNECTION_BIND);
++  LOG_LINK(LOG_CONNECTION, LOG_CONNECTION_FD);
++  LOG_LINK(LOG_CONNECTION, LOG_CONNECTION_FILTER);
++  LOG_LINK(LOG_CONNECTION, LOG_CONNECTION_HANDSHAKE);
++  LOG_LINK(LOG_CONNECTION, LOG_CONNECTION_LISTEN);
++
+   LOG_LINK(LOG_DHT_ALL, LOG_DHT_MANAGER);
+   LOG_LINK(LOG_DHT_ALL, LOG_DHT_NODE);
+   LOG_LINK(LOG_DHT_ALL, LOG_DHT_ROUTER);
+@@ -447,21 +410,4 @@ log_open_gz_file_output(const char* name, const char* filename, bool append) {
+                                   std::placeholders::_3));
+ }
+ 
+-log_buffer*
+-log_open_log_buffer(const char* name) {
+-  log_buffer* buffer = new log_buffer;
+-
+-  try {
+-    log_open_output(name, std::bind(&log_buffer::lock_and_push_log, buffer,
+-                                    std::placeholders::_1,
+-                                    std::placeholders::_2,
+-                                    std::placeholders::_3));
+-    return buffer;
+-
+-  } catch (torrent::input_error& e) {
+-    delete buffer;
+-    throw;
+-  }
+-}
+-
+ }
+diff --git a/src/torrent/utils/log.h b/src/torrent/utils/log.h
+index 0dfdc86b..fe6127d6 100644
+--- a/src/torrent/utils/log.h
++++ b/src/torrent/utils/log.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_UTILS_LOG_H
+ #define LIBTORRENT_UTILS_LOG_H
+ 
++#include <array>
+ #include <bitset>
++#include <functional>
+ #include <string>
+ #include <vector>
+-#include lt_tr1_array
+-#include lt_tr1_functional
++
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+@@ -55,13 +20,6 @@ enum {
+   LOG_INFO,
+   LOG_DEBUG,
+ 
+-  LOG_CONNECTION_CRITICAL,
+-  LOG_CONNECTION_ERROR,
+-  LOG_CONNECTION_WARN,
+-  LOG_CONNECTION_NOTICE,
+-  LOG_CONNECTION_INFO,
+-  LOG_CONNECTION_DEBUG,
+-
+   LOG_DHT_CRITICAL,
+   LOG_DHT_ERROR,
+   LOG_DHT_WARN,
+@@ -113,6 +71,14 @@ enum {
+ 
+   LOG_NON_CASCADING,
+ 
++  LOG_CONNECTION,
++  LOG_CONNECTION_BIND,
++  LOG_CONNECTION_FD,
++  LOG_CONNECTION_FILTER,
++  LOG_CONNECTION_HANDSHAKE,
++  LOG_CONNECTION_LISTEN,
++
++  // TODO: Rename dht_all to just dht.
+   LOG_DHT_ALL,
+   LOG_DHT_MANAGER,
+   LOG_DHT_NODE,
+@@ -125,7 +91,10 @@ enum {
+   LOG_INSTRUMENTATION_POLLING,
+   LOG_INSTRUMENTATION_TRANSFERS,
+ 
++  LOG_MOCK_CALLS,
++
+   LOG_PEER_LIST_EVENTS,
++  LOG_PEER_LIST_ADDRESS,
+ 
+   LOG_PROTOCOL_PIECE_EVENTS,
+   LOG_PROTOCOL_METADATA_EVENTS,
+@@ -137,6 +106,8 @@ enum {
+   LOG_RPC_EVENTS,
+   LOG_RPC_DUMP,
+ 
++  LOG_SYSTEM,
++
+   LOG_UI_EVENTS,
+ 
+   LOG_GROUP_MAX_SIZE
+@@ -145,34 +116,32 @@ enum {
+ #define lt_log_is_valid(log_group) (torrent::log_groups[log_group].valid())
+ 
+ #define lt_log_print(log_group, ...)                                    \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(NULL, NULL, NULL, 0, __VA_ARGS__);
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(NULL, NULL, NULL, 0, __VA_ARGS__); }
+ 
+ #define lt_log_print_info(log_group, log_info, log_subsystem, ...)      \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(&log_info->hash(), log_subsystem, NULL, 0, __VA_ARGS__);
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(&log_info->hash(), log_subsystem, NULL, 0, __VA_ARGS__); }
+ 
+ #define lt_log_print_data(log_group, log_data, log_subsystem, ...)      \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(&log_data->hash(), log_subsystem, NULL, 0, __VA_ARGS__);
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(&log_data->hash(), log_subsystem, NULL, 0, __VA_ARGS__); }
+ 
+ #define lt_log_print_dump(log_group, log_dump_data, log_dump_size, ...) \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(NULL, NULL, log_dump_data, log_dump_size, __VA_ARGS__); \
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(NULL, NULL, log_dump_data, log_dump_size, __VA_ARGS__); }
+ 
+ #define lt_log_print_hash(log_group, log_hash, log_subsystem, ...)      \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(&log_hash, log_subsystem, NULL, 0, __VA_ARGS__);
++  { if (torrent::log_groups[log_group].valid())                         \
++    torrent::log_groups[log_group].internal_print(&log_hash, log_subsystem, NULL, 0, __VA_ARGS__); }
+ 
+ #define lt_log_print_info_dump(log_group, log_dump_data, log_dump_size, log_info, log_subsystem, ...) \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(&log_info->hash(), log_subsystem, log_dump_data, log_dump_size, __VA_ARGS__); \
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(&log_info->hash(), log_subsystem, log_dump_data, log_dump_size, __VA_ARGS__); }
+ 
+ #define lt_log_print_subsystem(log_group, log_subsystem, ...)           \
+-  if (torrent::log_groups[log_group].valid())                           \
+-    torrent::log_groups[log_group].internal_print(NULL, log_subsystem, NULL, 0, __VA_ARGS__);
+-
+-class log_buffer;
++  { if (torrent::log_groups[log_group].valid())                         \
++      torrent::log_groups[log_group].internal_print(NULL, log_subsystem, NULL, 0, __VA_ARGS__); }
+ 
+ typedef std::function<void (const char*, unsigned int, int)> log_slot;
+ 
+@@ -222,7 +191,7 @@ private:
+ 
+ typedef std::array<log_group, LOG_GROUP_MAX_SIZE> log_group_list;
+ 
+-extern log_group_list  log_groups LIBTORRENT_EXPORT;
++extern log_group_list log_groups LIBTORRENT_EXPORT;
+ 
+ void log_initialize() LIBTORRENT_EXPORT;
+ void log_cleanup() LIBTORRENT_EXPORT;
+@@ -237,9 +206,8 @@ void log_remove_group_output(int group, const char* name) LIBTORRENT_EXPORT;
+ void log_add_child(int group, int child) LIBTORRENT_EXPORT;
+ void log_remove_child(int group, int child) LIBTORRENT_EXPORT;
+ 
+-void        log_open_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
+-void        log_open_gz_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
+-log_buffer* log_open_log_buffer(const char* name) LIBTORRENT_EXPORT;
++void log_open_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
++void log_open_gz_file_output(const char* name, const char* filename, bool append = false) LIBTORRENT_EXPORT;
+ 
+ //
+ // Implementation:
+diff --git a/src/torrent/utils/log_buffer.cc b/src/torrent/utils/log_buffer.cc
+index f82d57e0..5bf159a4 100644
+--- a/src/torrent/utils/log_buffer.cc
++++ b/src/torrent/utils/log_buffer.cc
+@@ -1,46 +1,8 @@
+-// 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 "log_buffer.h"
+ 
+-#include <functional>
+-#include lt_tr1_functional
+-
++#include "log.h"
+ #include "globals.h"
+ 
+ namespace torrent {
+@@ -72,4 +34,19 @@ log_buffer::lock_and_push_log(const char* data, size_t length, int group) {
+   unlock();
+ }
+ 
++static void
++log_buffer_deleter(log_buffer* lb) {
++  delete lb;
++}
++
++log_buffer_ptr
++log_open_log_buffer(const char* name) {
++  // TODO: Deregister when deleting.
++  auto buffer = log_buffer_ptr(new log_buffer, std::bind(&log_buffer_deleter, std::placeholders::_1));
++
++  log_open_output(name, std::bind(&log_buffer::lock_and_push_log, buffer.get(),
++                                  std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
++  return buffer;
++}
++
+ }
+diff --git a/src/torrent/utils/log_buffer.h b/src/torrent/utils/log_buffer.h
+index befd780b..259e5910 100644
+--- a/src/torrent/utils/log_buffer.h
++++ b/src/torrent/utils/log_buffer.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_UTILS_LOG_BUFFER_H
+-#define LIBTORRENT_UTILS_LOG_BUFFER_H
++#ifndef LIBTORRENT_TORRENT_UTILS_LOG_BUFFER_H
++#define LIBTORRENT_TORRENT_UTILS_LOG_BUFFER_H
+ 
+ #include <string>
+ #include <deque>
++#include <functional>
++#include <memory>
+ #include <pthread.h>
+-#include lt_tr1_functional
+-#include <torrent/common.h>
+ 
+ namespace torrent {
+ 
+@@ -57,9 +21,9 @@ struct log_entry {
+   std::string message;
+ };
+ 
+-class LIBTORRENT_EXPORT log_buffer : private std::deque<log_entry> {
++class [[gnu::visibility("default")]] log_buffer : private std::deque<log_entry> {
+ public:
+-  typedef std::deque<log_entry>       base_type;
++  typedef std::deque<log_entry>  base_type;
+   typedef std::function<void ()> slot_void;
+ 
+   using base_type::iterator;
+@@ -97,6 +61,10 @@ private:
+   slot_void           m_slot_update;
+ };
+ 
++typedef std::unique_ptr<log_buffer, std::function<void (log_buffer*)>> log_buffer_ptr;
++
++[[gnu::visibility("default")]] log_buffer_ptr log_open_log_buffer(const char* name);
++
+ }
+ 
+ #endif
+diff --git a/src/torrent/utils/net.cc b/src/torrent/utils/net.cc
+deleted file mode 100644
+index 83c9b506..00000000
+--- a/src/torrent/utils/net.cc
++++ /dev/null
+@@ -1,72 +0,0 @@
+-// 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 "net.h"
+-#include "exceptions.h"
+-
+-#include <cstring>
+-
+-namespace torrent {
+-
+-addrinfo*
+-address_info_lookup(const char* hostname, int family, int socktype) {
+-  addrinfo hints;
+-  std::memset(&hints, 0, sizeof(addrinfo));
+-  hints.ai_family = family;
+-  hints.ai_socktype = socktype;
+-  
+-  addrinfo* res = NULL;
+-  int err = ::getaddrinfo(hostname, NULL, &hints, &res);
+-
+-  if (err)
+-    throw address_info_error(err);
+-
+-  return res;
+-}
+-
+-bool
+-address_info_call(addrinfo* ai, int flags, slot_ai_success slot_success) {
+-  while (ai != NULL) {
+-    slot_success(ai->ai_addr, ai->ai_addrlen);
+-    return true;
+-  }
+-
+-  return false;
+-}
+-
+-}
+diff --git a/src/torrent/utils/net.h b/src/torrent/utils/net.h
+deleted file mode 100644
+index f5af7cc0..00000000
+--- a/src/torrent/utils/net.h
++++ /dev/null
+@@ -1,56 +0,0 @@
+-// 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_UTILS_NET_H
+-#define LIBTORRENT_UTILS_NET_H
+-
+-#include <netdb.h>
+-#include lt_tr1_functional
+-
+-namespace torrent {
+-
+-typedef std::function<void (sockaddr*, socklen_t)> slot_ai_success;
+-//typedef std::function<void (const char*, int)>     slot_ai_failure;
+-
+-// Throws address_info_error on lookup failure.
+-addrinfo*   address_info_lookup(const char* hostname, int family, int socktype);
+-inline void address_info_free(addrinfo* ai) { ::freeaddrinfo(ai); }
+-
+-bool        address_info_call(addrinfo* ai, int flags, slot_ai_success slot_success);
+-
+-}
+-
+-#endif
+diff --git a/src/torrent/utils/option_strings.cc b/src/torrent/utils/option_strings.cc
+index 5992cf37..101e2688 100644
+--- a/src/torrent/utils/option_strings.cc
++++ b/src/torrent/utils/option_strings.cc
+@@ -62,7 +62,7 @@ struct option_pair {
+   unsigned int value;
+ };
+ 
+-option_pair option_list_connection[] = {
++option_pair option_list_connection_type[] = {
+   { "leech",        Download::CONNECTION_LEECH },
+   { "seed",         Download::CONNECTION_SEED },
+   { "initial_seed", Download::CONNECTION_INITIAL_SEED },
+@@ -124,6 +124,19 @@ option_pair option_list_tracker_mode[] = {
+   { NULL, 0 }
+ };
+ 
++const char* option_list_handshake_connection[] = {
++  "none",
++  "incoming",
++  "outgoing_normal",
++  "outgoing_encrypted",
++  "outgoing_proxy",
++  "success",
++  "dropped",
++  "failed",
++  "retry_plaintext",
++  "retry_encrypted"
++};
++
+ const char* option_list_log_group[] = {
+   "critical",
+   "error",
+@@ -132,13 +145,6 @@ const char* option_list_log_group[] = {
+   "info",
+   "debug",
+   
+-  "connection_critical",
+-  "connection_error",
+-  "connection_warn",
+-  "connection_notice",
+-  "connection_info",
+-  "connection_debug",
+-  
+   "dht_critical",
+   "dht_error",
+   "dht_warn",
+@@ -190,6 +196,13 @@ const char* option_list_log_group[] = {
+ 
+   "__non_cascading__",
+ 
++  "connection",
++  "connection_bind",
++  "connection_fd",
++  "connection_filter",
++  "connection_hanshake",
++  "connection_listen",
++
+   "dht_all",
+   "dht_manager",
+   "dht_node",
+@@ -202,7 +215,10 @@ const char* option_list_log_group[] = {
+   "instrumentation_polling",
+   "instrumentation_transfers",
+ 
++  "mock_calls",
++
+   "peer_list_events",
++  "peer_list_address",
+ 
+   "protocol_piece_events",
+   "protocol_metadata_events",
+@@ -214,6 +230,8 @@ const char* option_list_log_group[] = {
+   "rpc_events",
+   "rpc_dump",
+ 
++  "system",
++
+   "ui_events",
+ 
+   NULL
+@@ -230,7 +248,7 @@ const char* option_list_tracker_event[] = {
+ };
+ 
+ option_pair* option_pair_lists[OPTION_START_COMPACT] = {
+-  option_list_connection,
++  option_list_connection_type,
+   option_list_heuristics,
+   option_list_heuristics_download,
+   option_list_heuristics_upload,
+@@ -244,6 +262,7 @@ option_pair* option_pair_lists[OPTION_START_COMPACT] = {
+   { sizeof(single_name) / sizeof(const char*) - 1, single_name }
+ 
+ option_single option_single_lists[OPTION_SINGLE_SIZE] = {
++  OPTION_SINGLE_ENTRY(option_list_handshake_connection),
+   OPTION_SINGLE_ENTRY(option_list_log_group),
+   OPTION_SINGLE_ENTRY(option_list_tracker_event),
+ };
+@@ -267,11 +286,11 @@ option_find_string(option_enum opt_enum, const char* name) {
+     } while (*++itr != NULL);
+   }
+ 
+-  throw input_error("Invalid option name.");  
++  throw input_error("Invalid option name.");
+ }
+ 
+ const char*
+-option_as_string(option_enum opt_enum, unsigned int value) {
++option_to_string(option_enum opt_enum, unsigned int value, const char* not_found) {
+   if (opt_enum < OPTION_START_COMPACT) {
+     option_pair* itr = option_pair_lists[opt_enum];
+   
+@@ -285,7 +304,27 @@ option_as_string(option_enum opt_enum, unsigned int value) {
+       return option_single_lists[opt_enum - OPTION_START_COMPACT].name[value];
+   }
+ 
+-  throw input_error("Invalid option value.");  
++  return not_found;
++}
++
++const char*
++option_to_string_or_throw(option_enum opt_enum, unsigned int value, const char* not_found) {
++  const char* result = option_to_string(opt_enum, value, NULL);
++
++  if (result == NULL)
++    throw input_error(not_found);
++  else
++    return result;
++}
++
++const char*
++option_as_string(option_enum opt_enum, unsigned int value) {
++  const char* result = option_to_string(opt_enum, value, NULL);
++
++  if (result == NULL)
++    throw input_error("Invalid option value.");
++  else
++    return result;
+ }
+ 
+ torrent::Object
+diff --git a/src/torrent/utils/option_strings.h b/src/torrent/utils/option_strings.h
+index 1b57efa8..f9e5ef77 100644
+--- a/src/torrent/utils/option_strings.h
++++ b/src/torrent/utils/option_strings.h
+@@ -54,17 +54,22 @@ enum option_enum {
+   OPTION_IP_TOS,
+   OPTION_TRACKER_MODE,
+ 
++  OPTION_HANDSHAKE_CONNECTION,
+   OPTION_LOG_GROUP,
+   OPTION_TRACKER_EVENT,
+ 
+   OPTION_MAX_SIZE,
+-  OPTION_START_COMPACT = OPTION_LOG_GROUP,
++  OPTION_START_COMPACT = OPTION_HANDSHAKE_CONNECTION,
+   OPTION_SINGLE_SIZE = OPTION_MAX_SIZE - OPTION_START_COMPACT
+ };
+ 
+ int             option_find_string(option_enum opt_enum, const char* name) LIBTORRENT_EXPORT;
+ inline int      option_find_string_str(option_enum opt_enum, const std::string& name) { return option_find_string(opt_enum, name.c_str()); }
+ 
++const char*     option_to_string(option_enum opt_enum, unsigned int value, const char* not_found = "invalid") LIBTORRENT_EXPORT;
++const char*     option_to_string_or_throw(option_enum opt_enum, unsigned int value, const char* not_found = "Invalid option value") LIBTORRENT_EXPORT;
++
++// TODO: Deprecated.
+ const char*     option_as_string(option_enum opt_enum, unsigned int value) LIBTORRENT_EXPORT;
+ 
+ torrent::Object option_list_strings(option_enum opt_enum) LIBTORRENT_EXPORT;
+diff --git a/src/torrent/utils/random.cc b/src/torrent/utils/random.cc
+new file mode 100644
+index 00000000..6a045429
+--- /dev/null
++++ b/src/torrent/utils/random.cc
+@@ -0,0 +1,29 @@
++#include "config.h"
++
++#include "random.h"
++
++#include "torrent/exceptions.h"
++
++namespace torrent {
++
++// TODO: Replace with std and thread_local generator.
++
++template <typename T>
++T
++random_uniform_template(T min, T max) {
++  if (min > max)
++    throw internal_error("random_uniform: min > max");
++
++  if (min == max)
++    return min;
++
++  std::random_device rd;
++  std::mt19937 mt(rd());
++
++  return min + std::uniform_int_distribution<T>(min, max)(mt) % (max - min + 1);
++}  
++
++uint16_t random_uniform_uint16(uint16_t min, uint16_t max) { return random_uniform_template<uint16_t>(min, max); }
++uint32_t random_uniform_uint32(uint32_t min, uint32_t max) { return random_uniform_template<uint32_t>(min, max); }
++
++}
+diff --git a/src/torrent/utils/random.h b/src/torrent/utils/random.h
+new file mode 100644
+index 00000000..d5992ab6
+--- /dev/null
++++ b/src/torrent/utils/random.h
+@@ -0,0 +1,15 @@
++#ifndef LIBTORRENT_TORRENT_UTILS_RANDOM_H
++#define LIBTORRENT_TORRENT_UTILS_RANDOM_H
++
++#include <cinttypes>
++#include <limits>
++#include <random>
++
++namespace torrent {
++
++[[gnu::weak]] [[gnu::visibility("default")]] uint16_t random_uniform_uint16(uint16_t min = std::numeric_limits<uint16_t>::min(), uint16_t max = std::numeric_limits<uint16_t>::max());
++[[gnu::weak]] [[gnu::visibility("default")]] uint32_t random_uniform_uint32(uint32_t min = std::numeric_limits<uint32_t>::min(), uint32_t max = std::numeric_limits<uint32_t>::max());
++
++}
++
++#endif
+diff --git a/src/torrent/utils/ranges.h b/src/torrent/utils/ranges.h
+index e784b084..7b1f8cb0 100644
+--- a/src/torrent/utils/ranges.h
++++ b/src/torrent/utils/ranges.h
+@@ -40,7 +40,6 @@
+ #include <algorithm>
+ #include <vector>
+ 
+-// TODO: Use tr1 functional instead.
+ #include <rak/functional.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/utils/resume.cc b/src/torrent/utils/resume.cc
+index 3f528c14..f8467d54 100644
+--- a/src/torrent/utils/resume.cc
++++ b/src/torrent/utils/resume.cc
+@@ -34,8 +34,6 @@
+ //           Skomakerveien 33
+ //           3185 Skoppum, NORWAY
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include "config.h"
+ 
+ #include <rak/file_stat.h>
+diff --git a/src/torrent/utils/signal_bitfield.h b/src/torrent/utils/signal_bitfield.h
+index b9f57a60..ffa336d2 100644
+--- a/src/torrent/utils/signal_bitfield.h
++++ b/src/torrent/utils/signal_bitfield.h
+@@ -37,7 +37,8 @@
+ #ifndef LIBTORRENT_UTILS_SIGNAL_BITFIELD_H
+ #define LIBTORRENT_UTILS_SIGNAL_BITFIELD_H
+ 
+-#include lt_tr1_functional
++#include <functional>
++
+ #include <torrent/common.h>
+ 
+ namespace torrent {
+diff --git a/src/torrent/utils/thread_base.h b/src/torrent/utils/thread_base.h
+index bfd443ae..b92a98ba 100644
+--- a/src/torrent/utils/thread_base.h
++++ b/src/torrent/utils/thread_base.h
+@@ -37,11 +37,12 @@
+ #ifndef LIBTORRENT_UTILS_THREAD_BASE_H
+ #define LIBTORRENT_UTILS_THREAD_BASE_H
+ 
++#include <functional>
+ #include <pthread.h>
+ #include <sys/types.h>
++
+ #include <torrent/common.h>
+ #include <torrent/utils/signal_bitfield.h>
+-#include lt_tr1_functional
+ 
+ namespace torrent {
+ 
+diff --git a/src/utils/instrumentation.cc b/src/utils/instrumentation.cc
+index 729b20e2..178d6a19 100644
+--- a/src/utils/instrumentation.cc
++++ b/src/utils/instrumentation.cc
+@@ -36,8 +36,6 @@
+ 
+ #include "config.h"
+ 
+-#define __STDC_FORMAT_MACROS
+-
+ #include "instrumentation.h"
+ 
+ namespace torrent {
+diff --git a/src/utils/instrumentation.h b/src/utils/instrumentation.h
+index 956429bf..11e77f6d 100644
+--- a/src/utils/instrumentation.h
++++ b/src/utils/instrumentation.h
+@@ -37,9 +37,8 @@
+ #ifndef LIBTORRENT_UTILS_INSTRUMENTATION_H
+ #define LIBTORRENT_UTILS_INSTRUMENTATION_H
+ 
+-#include lt_tr1_array
+-
+ #include <algorithm>
++#include <array>
+ 
+ #include "torrent/common.h"
+ #include "torrent/utils/log.h"
+diff --git a/src/utils/queue_buckets.h b/src/utils/queue_buckets.h
+index de8584ff..b9174f27 100644
+--- a/src/utils/queue_buckets.h
++++ b/src/utils/queue_buckets.h
+@@ -38,9 +38,9 @@
+ #define LIBTORRENT_QUEUE_BUCKETS_H
+ 
+ #include <algorithm>
++#include <array>
+ #include <deque>
+-#include lt_tr1_functional
+-#include lt_tr1_array
++#include <functional>
+ 
+ namespace torrent {
+ 
+diff --git a/src/utils/sha_fast.h b/src/utils/sha_fast.h
+index f7ce3b87..eb357864 100644
+--- a/src/utils/sha_fast.h
++++ b/src/utils/sha_fast.h
+@@ -41,7 +41,7 @@
+ #ifndef _SHA_FAST_H_
+ #define _SHA_FAST_H_
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ 
+ namespace torrent {
+ 
+diff --git a/test/Makefile.am b/test/Makefile.am
+index d7a9d5b3..b60a86a6 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -18,6 +18,17 @@ LibTorrentTest_LDADD = \
+ 	../src/torrent/utils/libsub_torrentutils.la
+ 
+ LibTorrentTest_SOURCES = \
++	helpers/expect_fd.h \
++	helpers/expect_utils.h \
++	helpers/mock_compare.h \
++	helpers/mock_function.cc \
++	helpers/mock_function.h \
++	helpers/network.h \
++	helpers/progress_listener.cc \
++	helpers/progress_listener.h \
++	helpers/test_fixture.cc \
++	helpers/test_fixture.h \
++	\
+ 	../src/thread_disk.cc \
+ 	../src/thread_disk.h \
+ 	\
+@@ -31,22 +42,28 @@ LibTorrentTest_SOURCES = \
+ 	data/hash_check_queue_test.h \
+ 	data/hash_queue_test.cc \
+ 	data/hash_queue_test.h \
++	\
++	net/test_socket_listen.cc \
++	net/test_socket_listen.h \
++	\
+ 	protocol/test_request_list.cc \
+ 	protocol/test_request_list.h \
+ 	\
+-	torrent/net/test_socket_address_key.cc \
+-	torrent/net/test_socket_address_key.h \
++	torrent/net/test_address_info.cc \
++	torrent/net/test_address_info.h \
++	torrent/net/test_fd.cc \
++	torrent/net/test_fd.h \
++	torrent/net/test_socket_address.cc \
++	torrent/net/test_socket_address.h \
+ 	\
+ 	torrent/utils/log_test.cc \
+ 	torrent/utils/log_test.h \
+-	torrent/utils/log_buffer_test.cc \
+-	torrent/utils/log_buffer_test.h \
+-	torrent/utils/net_test.cc \
+-	torrent/utils/net_test.h \
+ 	torrent/utils/option_strings_test.cc \
+ 	torrent/utils/option_strings_test.h \
+ 	torrent/utils/test_extents.cc \
+ 	torrent/utils/test_extents.h \
++	torrent/utils/test_log_buffer.cc \
++	torrent/utils/test_log_buffer.h \
+ 	torrent/utils/test_queue_buckets.cc \
+ 	torrent/utils/test_queue_buckets.h \
+ 	torrent/utils/test_uri_parser.cc \
+diff --git a/test/data/hash_check_queue_test.cc b/test/data/hash_check_queue_test.cc
+index c6bdeaec..4b15245e 100644
+--- a/test/data/hash_check_queue_test.cc
++++ b/test/data/hash_check_queue_test.cc
+@@ -1,7 +1,7 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <signal.h>
+-#include lt_tr1_functional
+ 
+ #include "data/hash_queue_node.h"
+ #include "utils/sha1.h"
+diff --git a/test/data/hash_queue_test.cc b/test/data/hash_queue_test.cc
+index 287c28e9..d7ce3ba8 100644
+--- a/test/data/hash_queue_test.cc
++++ b/test/data/hash_queue_test.cc
+@@ -1,7 +1,7 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <signal.h>
+-#include lt_tr1_functional
+ 
+ #include "data/hash_queue_node.h"
+ #include "torrent/chunk_manager.h"
+diff --git a/test/helpers/expect_fd.h b/test/helpers/expect_fd.h
+new file mode 100644
+index 00000000..178cbabc
+--- /dev/null
++++ b/test/helpers/expect_fd.h
+@@ -0,0 +1,107 @@
++#ifndef LIBTORRENT_HELPER_EXPECT_FD_H
++#define LIBTORRENT_HELPER_EXPECT_FD_H
++
++#include "helpers/mock_function.h"
++
++#include <fcntl.h>
++#include <torrent/event.h>
++#include <torrent/net/fd.h>
++#include <torrent/net/socket_address.h>
++
++typedef std::vector<torrent::sa_unique_ptr> sap_cache_type;
++
++inline const sockaddr*
++sap_cache_copy_addr_c_ptr(sap_cache_type& sap_cache, const torrent::c_sa_unique_ptr& sap, uint16_t port = 0) {
++  sap_cache.push_back(torrent::sap_copy_addr(sap, port));
++  return sap_cache.back().get();
++}
++
++inline void
++expect_event_open_re(int idx) {
++  mock_expect(&torrent::poll_event_open, mock_compare_map<torrent::Event>::begin_pointer + idx);
++  mock_expect(&torrent::poll_event_insert_read, mock_compare_map<torrent::Event>::begin_pointer + idx);
++  mock_expect(&torrent::poll_event_insert_error, mock_compare_map<torrent::Event>::begin_pointer + idx);
++}
++
++inline void
++expect_event_closed_fd(int idx, int fd) {
++  mock_expect(&torrent::fd__close, 0, fd);
++  mock_expect(&torrent::poll_event_closed, mock_compare_map<torrent::Event>::begin_pointer + idx);
++}
++
++inline void
++expect_fd_inet_tcp(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++}
++
++inline void
++expect_fd_inet6_tcp(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET6, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++}
++
++inline void
++expect_fd_inet_tcp_nonblock(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++}
++
++inline void
++expect_fd_inet6_tcp_nonblock(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET6, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++}
++
++inline void
++expect_fd_inet_tcp_nonblock_reuseaddr(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++  mock_expect(&torrent::fd__setsockopt_int, 0, fd, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++}
++
++inline void
++expect_fd_inet6_tcp_nonblock_reuseaddr(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET6, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++  mock_expect(&torrent::fd__setsockopt_int, 0, fd, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++}
++
++inline void
++expect_fd_inet6_tcp_v6only_nonblock(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET6, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__setsockopt_int, 0, fd, (int)IPPROTO_IPV6, (int)IPV6_V6ONLY, (int)true);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++}
++
++inline void
++expect_fd_inet6_tcp_v6only_nonblock_reuseaddr(int fd) {
++  mock_expect(&torrent::fd__socket, fd, (int)PF_INET6, (int)SOCK_STREAM, (int)IPPROTO_TCP);
++  mock_expect(&torrent::fd__setsockopt_int, 0, fd, (int)IPPROTO_IPV6, (int)IPV6_V6ONLY, (int)true);
++  mock_expect(&torrent::fd__fcntl_int, 0, fd, F_SETFL, O_NONBLOCK);
++  mock_expect(&torrent::fd__setsockopt_int, 0, fd, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++}
++
++inline void
++expect_fd_bind_connect(int fd, const torrent::c_sa_unique_ptr& bind_sap, const torrent::c_sa_unique_ptr& connect_sap) {
++  mock_expect(&torrent::fd__bind, 0, fd, bind_sap.get(), (socklen_t)torrent::sap_length(bind_sap));
++  mock_expect(&torrent::fd__connect, 0, fd, connect_sap.get(), (socklen_t)torrent::sap_length(connect_sap));
++}
++
++inline void
++expect_fd_bind_fail_range(int fd, sap_cache_type& sap_cache, const torrent::c_sa_unique_ptr& sap, uint16_t first_port, uint16_t last_port) {
++  do {
++    mock_expect(&torrent::fd__bind, -1, fd, sap_cache_copy_addr_c_ptr(sap_cache, sap, first_port), (socklen_t)torrent::sap_length(sap));
++  } while (first_port++ != last_port);
++}
++
++inline void
++expect_fd_bind_listen(int fd, const torrent::c_sa_unique_ptr& sap) {
++  mock_expect(&torrent::fd__bind, 0, fd, sap.get(), (socklen_t)torrent::sap_length(sap));
++  mock_expect(&torrent::fd__listen, 0, fd, SOMAXCONN);
++}
++
++inline void
++expect_fd_connect(int fd, const torrent::c_sa_unique_ptr& sap) {
++  mock_expect(&torrent::fd__connect, 0, fd, sap.get(), (socklen_t)torrent::sap_length(sap));
++}
++
++#endif
+diff --git a/test/helpers/expect_utils.h b/test/helpers/expect_utils.h
+new file mode 100644
+index 00000000..c84a11e0
+--- /dev/null
++++ b/test/helpers/expect_utils.h
+@@ -0,0 +1,13 @@
++#ifndef LIBTORRENT_HELPER_EXPECT_UTILS_H
++#define LIBTORRENT_HELPER_EXPECT_UTILS_H
++
++#include "helpers/mock_function.h"
++
++#include <torrent/utils/random.h>
++
++inline void
++expect_random_uniform_uint16(uint16_t result, uint16_t first, uint16_t last) {
++  mock_expect(&torrent::random_uniform_uint16, result, first, last);
++}
++
++#endif
+diff --git a/test/helpers/mock_compare.h b/test/helpers/mock_compare.h
+new file mode 100644
+index 00000000..3ea90305
+--- /dev/null
++++ b/test/helpers/mock_compare.h
+@@ -0,0 +1,96 @@
++#ifndef LIBTORRENT_HELPERS_MOCK_COMPARE_H
++#define LIBTORRENT_HELPERS_MOCK_COMPARE_H
++
++#include <algorithm>
++#include <type_traits>
++#include <torrent/event.h>
++#include <torrent/net/socket_address.h>
++
++// Compare arguments to mock functions with what is expected. The lhs
++// are the expected arguments, rhs are the ones called with.
++
++template <typename Arg>
++inline bool mock_compare_arg(Arg lhs, Arg rhs) { return lhs == rhs; }
++
++template <int I, typename A, typename... Args>
++typename std::enable_if<I == 1, int>::type
++mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
++  return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : 1;
++}
++
++template <int I, typename A, typename... Args>
++typename std::enable_if<1 < I, int>::type
++mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
++  auto res = mock_compare_tuple<I - 1>(lhs, rhs);
++
++  if (res != 0)
++    return res;
++
++  return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : I;
++}
++
++//template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 0>
++template <typename T>
++struct mock_compare_map {
++  typedef std::map<const T*, const T*> values_type;
++
++  constexpr static T* begin_pointer = reinterpret_cast<T*>(0x1000);
++  constexpr static T* end_pointer = reinterpret_cast<T*>(0x2000);
++
++  static bool is_key(const T* k) {
++    return k >= begin_pointer && k < end_pointer;
++  }
++
++  static bool has_key(const T* k) {
++    return values.find(k) != values.end();
++  }
++
++  static bool has_value(const T* v) {
++    return std::find_if(values.begin(), values.end(), [v](typename values_type::value_type& kv) { return v == kv.second; }) != values.end();
++  }
++
++  static const T* get(const T* k) {
++    auto itr = values.find(k);
++    CPPUNIT_ASSERT_MESSAGE("mock_compare_map get failed, not inserted", itr != values.end());
++    return itr->second;
++  }
++
++  static values_type values;
++};
++
++template<typename T>
++typename mock_compare_map<T>::values_type mock_compare_map<T>::values;
++
++template<typename T>
++void mock_compare_add(T* v) {
++  mock_compare_map<T>::add_value(v);
++}
++
++//
++// Specialize:
++//
++
++template <>
++inline bool mock_compare_arg<sockaddr*>(sockaddr* lhs, sockaddr* rhs) {
++  return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
++}
++template <>
++inline bool mock_compare_arg<const sockaddr*>(const sockaddr* lhs, const sockaddr* rhs) {
++  return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
++}
++
++template <>
++inline bool mock_compare_arg<torrent::Event*>(torrent::Event* lhs, torrent::Event* rhs) {
++  if (mock_compare_map<torrent::Event>::is_key(lhs)) {
++    if (!mock_compare_map<torrent::Event>::has_value(rhs)) {
++      mock_compare_map<torrent::Event>::values[lhs] = rhs;
++      return true;
++    }
++    
++    return mock_compare_map<torrent::Event>::has_key(lhs) && mock_compare_map<torrent::Event>::get(lhs) == rhs;
++  }
++  
++  return lhs == rhs;
++}
++
++#endif
+diff --git a/test/helpers/mock_function.cc b/test/helpers/mock_function.cc
+new file mode 100644
+index 00000000..83e81551
+--- /dev/null
++++ b/test/helpers/mock_function.cc
+@@ -0,0 +1,170 @@
++#include "config.h"
++
++#include "mock_function.h"
++
++#include <fcntl.h>
++#include <iostream>
++#include <torrent/event.h>
++#include <torrent/net/socket_address.h>
++#include <torrent/net/fd.h>
++#include <torrent/utils/log.h>
++#include <torrent/utils/random.h>
++
++#define MOCK_CLEANUP_MAP(MOCK_FUNC) \
++  CPPUNIT_ASSERT_MESSAGE("expected mock function calls not completed for '" #MOCK_FUNC "'", mock_cleanup_map(&MOCK_FUNC) || ignore_assert);
++#define MOCK_LOG(log_fmt, ...)                                          \
++  lt_log_print(torrent::LOG_MOCK_CALLS, "%s: " log_fmt, __func__, __VA_ARGS__);
++
++void
++mock_clear(bool ignore_assert) {
++  MOCK_CLEANUP_MAP(torrent::fd__accept);
++  MOCK_CLEANUP_MAP(torrent::fd__bind);
++  MOCK_CLEANUP_MAP(torrent::fd__close);
++  MOCK_CLEANUP_MAP(torrent::fd__connect);
++  MOCK_CLEANUP_MAP(torrent::fd__fcntl_int);
++  MOCK_CLEANUP_MAP(torrent::fd__listen);
++  MOCK_CLEANUP_MAP(torrent::fd__setsockopt_int);
++  MOCK_CLEANUP_MAP(torrent::fd__socket);
++
++  MOCK_CLEANUP_MAP(torrent::poll_event_open);
++  MOCK_CLEANUP_MAP(torrent::poll_event_close);
++  MOCK_CLEANUP_MAP(torrent::poll_event_closed);
++  MOCK_CLEANUP_MAP(torrent::poll_event_insert_read);
++  MOCK_CLEANUP_MAP(torrent::poll_event_insert_write);
++  MOCK_CLEANUP_MAP(torrent::poll_event_insert_error);
++  MOCK_CLEANUP_MAP(torrent::poll_event_remove_read);
++  MOCK_CLEANUP_MAP(torrent::poll_event_remove_write);
++  MOCK_CLEANUP_MAP(torrent::poll_event_remove_error);
++
++  MOCK_CLEANUP_MAP(torrent::random_uniform_uint16);
++  MOCK_CLEANUP_MAP(torrent::random_uniform_uint32);
++
++  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);
++}
++
++namespace torrent {
++
++//
++// Mock functions for 'torrent/net/fd.h':
++//
++
++int fd__accept(int socket, sockaddr *address, socklen_t *address_len) {
++  MOCK_LOG("entry socket:%i address:%s address_len:%u",
++           socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
++  auto ret = mock_call<int>(__func__, &torrent::fd__accept, socket, address, address_len);
++  MOCK_LOG("exit socket:%i address:%s address_len:%u",
++           socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
++  return ret;
++}
++
++int fd__bind(int socket, const sockaddr *address, socklen_t address_len) {
++  MOCK_LOG("socket:%i address:%s address_len:%u",
++           socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
++  return mock_call<int>(__func__, &torrent::fd__bind, socket, address, address_len);
++}
++
++int fd__close(int fildes) {
++  MOCK_LOG("filedes:%i", fildes);
++  return mock_call<int>(__func__, &torrent::fd__close, fildes);
++}
++
++int fd__connect(int socket, const sockaddr *address, socklen_t address_len) {
++  MOCK_LOG("socket:%i address:%s address_len:%u",
++           socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
++  return mock_call<int>(__func__, &torrent::fd__connect, socket, address, address_len);
++}
++
++int fd__fcntl_int(int fildes, int cmd, int arg) {
++  MOCK_LOG("filedes:%i cmd:%i arg:%i", fildes, cmd, arg);
++  return mock_call<int>(__func__, &torrent::fd__fcntl_int, fildes, cmd, arg);
++}
++
++int fd__listen(int socket, int backlog) {
++  MOCK_LOG("socket:%i backlog:%i", socket, backlog);
++  return mock_call<int>(__func__, &torrent::fd__listen, socket, backlog);
++}
++
++int fd__setsockopt_int(int socket, int level, int option_name, int option_value) {
++  MOCK_LOG("socket:%i level:%i option_name:%i option_value:%i",
++           socket, level, option_name, option_value);
++  return mock_call<int>(__func__, &torrent::fd__setsockopt_int, socket, level, option_name, option_value);
++}
++
++int fd__socket(int domain, int type, int protocol) {
++  MOCK_LOG("domain:%i type:%i protocol:%i", domain, type, protocol);
++  return mock_call<int>(__func__, &torrent::fd__socket, domain, type, protocol);
++}
++
++//
++// Mock functions for 'torrent/event.h':
++//
++
++void poll_event_open(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_open, event);
++}
++
++void poll_event_close(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_close, event);
++}
++
++void poll_event_closed(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_closed, event);
++}
++
++void poll_event_insert_read(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_insert_read, event);
++}
++
++void poll_event_insert_write(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_insert_write, event);
++}
++
++void poll_event_insert_error(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_insert_error, event);
++}
++
++void poll_event_remove_read(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_remove_read, event);
++}
++
++void poll_event_remove_write(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_remove_write, event);
++}
++
++void poll_event_remove_error(Event* event) {
++  MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
++  return mock_call<void>(__func__, &torrent::poll_event_remove_error, event);
++}
++
++//
++// Mock functions for 'torrent/utils/random.h':
++//
++
++uint16_t random_uniform_uint16(uint16_t min, uint16_t max) {
++  MOCK_LOG("min:%" PRIu16 " max:%" PRIu16, min, max);
++  return mock_call<uint16_t>(__func__, &torrent::random_uniform_uint16, min, max);
++}
++
++uint32_t random_uniform_uint32(uint32_t min, uint32_t max) {
++  MOCK_LOG("min:%" PRIu32 " max:%" PRIu32, min, max);
++  return mock_call<uint32_t>(__func__, &torrent::random_uniform_uint32, min, max);
++}
++
++}
+diff --git a/test/helpers/mock_function.h b/test/helpers/mock_function.h
+new file mode 100644
+index 00000000..6c194137
+--- /dev/null
++++ b/test/helpers/mock_function.h
+@@ -0,0 +1,133 @@
++#ifndef LIBTORRENT_HELPERS_MOCK_FUNCTION_H
++#define LIBTORRENT_HELPERS_MOCK_FUNCTION_H
++
++#include <functional>
++#include <map>
++#include <string>
++#include <tuple>
++#include <type_traits>
++#include <utility>
++#include <cppunit/extensions/HelperMacros.h>
++
++#include "helpers/mock_compare.h"
++
++template<typename R, typename... Args>
++struct mock_function_map {
++  typedef std::tuple<R, Args...> call_type;
++  typedef std::vector<call_type> call_list_type;
++  typedef std::map<void*, call_list_type> func_map_type;
++
++  typedef std::function<R (Args...)> function_type;
++  typedef std::map<void*, function_type> redirect_map_type;
++
++  static func_map_type functions;
++  static redirect_map_type redirects;
++
++  static bool cleanup(void* fn) {
++    redirects.erase(fn);
++    return functions.erase(fn) == 0;
++  }
++
++  static R ret_erase(void* fn) {
++    auto itr = functions.find(fn);
++    auto ret = std::get<0>(itr->second.front());
++    itr->second.erase(itr->second.begin());
++
++    if (itr->second.empty())
++      functions.erase(itr);
++
++    return ret;
++  }
++};
++
++template<typename R, typename... Args>
++typename mock_function_map<R, Args...>::func_map_type mock_function_map<R, Args...>::functions;
++template<typename R, typename... Args>
++typename mock_function_map<R, Args...>::redirect_map_type mock_function_map<R, Args...>::redirects;
++
++struct mock_void {};
++
++template<typename R, typename... Args>
++struct mock_function_type {
++  typedef mock_function_map<R, Args...> type;
++
++  static int compare_expected(typename type::call_type lhs, Args... rhs) {
++    return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
++  }
++
++  static R    ret_erase(void* fn) { return type::ret_erase(fn); }
++  static bool has_redirect(void* fn) { return type::redirects.find(fn) != type::redirects.end(); }
++  static R    call_redirect(void* fn, Args... args) { return type::redirects.find(fn)->second(args...); }
++};
++
++template<typename... Args>
++struct mock_function_type<void, Args...> {
++  typedef mock_function_map<mock_void, Args...> type;
++
++  static int compare_expected(typename type::call_type lhs, Args... rhs) {
++    return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
++  }
++
++  static void ret_erase(void* fn) { type::ret_erase(fn); }
++  static bool has_redirect(void* fn) { return type::redirects.find(fn) != type::redirects.end(); }
++  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...)) {
++  return mock_function_type<R, Args...>::type::cleanup(reinterpret_cast<void*>(fn));
++}
++
++template<typename R, typename... Args>
++void
++mock_expect(R fn(Args...), R ret, Args... args) {
++  typedef mock_function_map<R, Args...> mock_map;
++  mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<R, Args...>(ret, args...));
++}
++
++template<typename... Args>
++void
++mock_expect(void fn(Args...), Args... args) {
++  typedef mock_function_map<mock_void, Args...> mock_map;
++  mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<mock_void, Args...>(mock_void(), args...));
++}
++
++template<typename R, typename... Args>
++void
++mock_redirect(R fn(Args...), std::function<R (Args...)> func) {
++  typedef mock_function_map<R, Args...> mock_map;
++  mock_map::redirects[reinterpret_cast<void*>(fn)] = func;
++}
++
++template<typename R, typename... Args>
++auto
++mock_call_direct(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
++  typedef mock_function_type<R, Args...> mock_type;
++
++  auto itr = mock_type::type::functions.find(reinterpret_cast<void*>(fn));
++  CPPUNIT_ASSERT_MESSAGE(("mock_call expected function calls exhausted by '" + name + "'").c_str(),
++                         itr != mock_type::type::functions.end());
++
++  auto mismatch_arg = mock_type::compare_expected(itr->second.front(), args...);
++  CPPUNIT_ASSERT_MESSAGE(("mock_call expected function call argument " + std::to_string(mismatch_arg) + " mismatch for '" + name + "'").c_str(),
++                         mismatch_arg == 0);
++
++  return mock_type::ret_erase(reinterpret_cast<void*>(fn));
++}
++
++template<typename R, typename... Args>
++auto
++mock_call(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
++  typedef mock_function_type<R, Args...> mock_type;
++
++  if (mock_type::has_redirect(reinterpret_cast<void*>(fn)))
++    return mock_type::call_redirect(reinterpret_cast<void*>(fn), args...);
++
++  return mock_call_direct(name, fn, args...);
++}
++
++#endif
+diff --git a/test/helpers/network.h b/test/helpers/network.h
+new file mode 100644
+index 00000000..6cf2f870
+--- /dev/null
++++ b/test/helpers/network.h
+@@ -0,0 +1,182 @@
++#ifndef LIBTORRENT_HELPER_NETWORK_H
++#define LIBTORRENT_HELPER_NETWORK_H
++
++#include <functional>
++#include <string>
++#include <cppunit/extensions/HelperMacros.h>
++
++#include "torrent/net/address_info.h"
++
++//
++// Socket addresses
++//
++
++#define TEST_DEFAULT_SA                                                 \
++  auto sin_any = wrap_ai_get_first_sa("0.0.0.0");                       \
++  auto sin_any_5000 = wrap_ai_get_first_sa("0.0.0.0", "5000");          \
++  auto sin_any_5005 = wrap_ai_get_first_sa("0.0.0.0", "5005");          \
++  auto sin_bc = wrap_ai_get_first_sa("255.255.255.255");                \
++  auto sin_bc_5000 = wrap_ai_get_first_sa("255.255.255.255", "5000");   \
++  auto sin_bnd = wrap_ai_get_first_sa("123.123.123.123");               \
++  auto sin_1 = wrap_ai_get_first_sa("1.2.3.4");                         \
++  auto sin_1_5000 = wrap_ai_get_first_sa("1.2.3.4", "5000");            \
++  auto sin_1_5005 = wrap_ai_get_first_sa("1.2.3.4", "5005");            \
++  auto sin_1_5100 = wrap_ai_get_first_sa("1.2.3.4", "5100");            \
++  auto sin_2      = wrap_ai_get_first_sa("4.3.2.1");                    \
++  auto sin_2_5000 = wrap_ai_get_first_sa("4.3.2.1", "5000");            \
++  auto sin_2_5100 = wrap_ai_get_first_sa("4.3.2.1", "5100");            \
++                                                                        \
++  auto sin6_any = wrap_ai_get_first_sa("::");                           \
++  auto sin6_any_5000 = wrap_ai_get_first_sa("::", "5000");              \
++  auto sin6_any_5005 = wrap_ai_get_first_sa("::", "5005");              \
++  auto sin6_bnd = wrap_ai_get_first_sa("ff01::123");                    \
++  auto sin6_1 = wrap_ai_get_first_sa("ff01::1");                        \
++  auto sin6_1_5000 = wrap_ai_get_first_sa("ff01::1", "5000");           \
++  auto sin6_1_5005 = wrap_ai_get_first_sa("ff01::1", "5005");           \
++  auto sin6_1_5100 = wrap_ai_get_first_sa("ff01::1", "5100");           \
++  auto sin6_2      = wrap_ai_get_first_sa("ff02::2");                   \
++  auto sin6_2_5000 = wrap_ai_get_first_sa("ff02::2", "5000");           \
++  auto sin6_2_5100 = wrap_ai_get_first_sa("ff02::2", "5100");           \
++  auto sin6_v4_1 = wrap_ai_get_first_sa("::ffff:1.2.3.4");              \
++  auto sin6_v4_1_5000 = wrap_ai_get_first_sa("::ffff:1.2.3.4", "5000"); \
++  auto sin6_v4_any = wrap_ai_get_first_sa("::ffff:0.0.0.0");            \
++  auto sin6_v4_any_5000 = wrap_ai_get_first_sa("::ffff:0.0.0.0", "5000"); \
++  auto sin6_v4_bc = wrap_ai_get_first_sa("::ffff:255.255.255.255");     \
++  auto sin6_v4_bc_5000 = wrap_ai_get_first_sa("::ffff:255.255.255.255", "5000"); \
++  auto sin6_v4_bnd = wrap_ai_get_first_sa("::ffff:123.123.123.123");    \
++                                                                        \
++  auto c_sin_any = wrap_ai_get_first_c_sa("0.0.0.0");                   \
++  auto c_sin_any_5000 = wrap_ai_get_first_c_sa("0.0.0.0", "5000");      \
++  auto c_sin_any_5005 = wrap_ai_get_first_c_sa("0.0.0.0", "5005");      \
++  auto c_sin_any_5010 = wrap_ai_get_first_c_sa("0.0.0.0", "5010");      \
++  auto c_sin_any_6881 = wrap_ai_get_first_c_sa("0.0.0.0", "6881");      \
++  auto c_sin_any_6900 = wrap_ai_get_first_c_sa("0.0.0.0", "6900");      \
++  auto c_sin_any_6999 = wrap_ai_get_first_c_sa("0.0.0.0", "6999");      \
++  auto c_sin_bc = wrap_ai_get_first_c_sa("255.255.255.255");            \
++  auto c_sin_bc_5000 = wrap_ai_get_first_c_sa("255.255.255.255", "5000"); \
++  auto c_sin_bnd = wrap_ai_get_first_c_sa("123.123.123.123");           \
++  auto c_sin_bnd_5000 = wrap_ai_get_first_c_sa("123.123.123.123", "5000"); \
++  auto c_sin_bnd_6881 = wrap_ai_get_first_c_sa("123.123.123.123", "6881"); \
++  auto c_sin_bnd_6900 = wrap_ai_get_first_c_sa("123.123.123.123", "6900"); \
++  auto c_sin_bnd_6999 = wrap_ai_get_first_c_sa("123.123.123.123", "6999"); \
++  auto c_sin_1 = wrap_ai_get_first_c_sa("1.2.3.4");                     \
++  auto c_sin_1_5000 = wrap_ai_get_first_c_sa("1.2.3.4", "5000");        \
++  auto c_sin_1_5005 = wrap_ai_get_first_c_sa("1.2.3.4", "5005");        \
++  auto c_sin_1_5010 = wrap_ai_get_first_c_sa("1.2.3.4", "5010");        \
++  auto c_sin_1_6881 = wrap_ai_get_first_c_sa("1.2.3.4", "6881");        \
++  auto c_sin_1_6900 = wrap_ai_get_first_c_sa("1.2.3.4", "6900");        \
++  auto c_sin_1_6999 = wrap_ai_get_first_c_sa("1.2.3.4", "6999");        \
++  auto c_sin_2      = wrap_ai_get_first_c_sa("4.3.2.1");                \
++  auto c_sin_2_5000 = wrap_ai_get_first_c_sa("4.3.2.1", "5000");        \
++  auto c_sin_2_5100 = wrap_ai_get_first_c_sa("4.3.2.1", "5100");        \
++                                                                        \
++  auto c_sin6_any = wrap_ai_get_first_c_sa("::");                       \
++  auto c_sin6_any_5000 = wrap_ai_get_first_c_sa("::", "5000");          \
++  auto c_sin6_any_5005 = wrap_ai_get_first_c_sa("::", "5005");          \
++  auto c_sin6_any_5010 = wrap_ai_get_first_c_sa("::", "5010");          \
++  auto c_sin6_any_6881 = wrap_ai_get_first_c_sa("::", "6881");          \
++  auto c_sin6_any_6900 = wrap_ai_get_first_c_sa("::", "6900");          \
++  auto c_sin6_any_6999 = wrap_ai_get_first_c_sa("::", "6999");          \
++  auto c_sin6_bnd = wrap_ai_get_first_c_sa("ff01::123");                \
++  auto c_sin6_bnd_5000 = wrap_ai_get_first_c_sa("ff01::123", "5000");   \
++  auto c_sin6_bnd_6881 = wrap_ai_get_first_c_sa("ff01::123", "6881");   \
++  auto c_sin6_bnd_6900 = wrap_ai_get_first_c_sa("ff01::123", "6900");   \
++  auto c_sin6_bnd_6999 = wrap_ai_get_first_c_sa("ff01::123", "6999");   \
++  auto c_sin6_v4_1_5000 = wrap_ai_get_first_c_sa("::ffff:1.2.3.4", "5000"); \
++  auto c_sin6_1 = wrap_ai_get_first_c_sa("ff01::1");                    \
++  auto c_sin6_1_5000 = wrap_ai_get_first_c_sa("ff01::1", "5000");       \
++  auto c_sin6_1_5005 = wrap_ai_get_first_c_sa("ff01::1", "5005");       \
++  auto c_sin6_1_5010 = wrap_ai_get_first_c_sa("ff01::1", "5010");       \
++  auto c_sin6_1_5100 = wrap_ai_get_first_c_sa("ff01::1", "5100");       \
++  auto c_sin6_1_6881 = wrap_ai_get_first_c_sa("ff01::1", "6881");       \
++  auto c_sin6_1_6900 = wrap_ai_get_first_c_sa("ff01::1", "6900");       \
++  auto c_sin6_1_6999 = wrap_ai_get_first_c_sa("ff01::1", "6999");       \
++  auto c_sin6_2      = wrap_ai_get_first_c_sa("ff02::2");               \
++  auto c_sin6_2_5000 = wrap_ai_get_first_c_sa("ff02::2", "5000");       \
++  auto c_sin6_2_5100 = wrap_ai_get_first_c_sa("ff02::2", "5100");
++
++inline bool
++compare_sin6_addr(in6_addr lhs, in6_addr rhs) {
++  return std::equal(lhs.s6_addr, lhs.s6_addr + 16, rhs.s6_addr);
++}
++
++inline bool
++compare_listen_result(const torrent::listen_result_type& lhs, int rhs_fd, const torrent::c_sa_unique_ptr& rhs_sap) {
++  return lhs.fd == rhs_fd &&
++    ((lhs.address && rhs_sap) || ((lhs.address && rhs_sap) && torrent::sap_equal(lhs.address, rhs_sap)));
++}
++
++inline torrent::sa_unique_ptr
++wrap_ai_get_first_sa(const char* nodename, const char* servname = nullptr, const addrinfo* hints = nullptr) {
++  auto sa = torrent::ai_get_first_sa(nodename, servname, hints);
++
++  CPPUNIT_ASSERT_MESSAGE(("wrap_ai_get_first_sa: nodename:'" + std::string(nodename) + "'").c_str(),
++                        sa != nullptr);
++  return sa;
++}
++
++inline torrent::c_sa_unique_ptr
++wrap_ai_get_first_c_sa(const char* nodename, const char* servname = nullptr, const addrinfo* hints = nullptr) {
++  auto sa = torrent::ai_get_first_sa(nodename, servname, hints);
++
++  CPPUNIT_ASSERT_MESSAGE(("wrap_ai_get_first_sa: nodename:'" + std::string(nodename) + "'").c_str(),
++                        sa != nullptr);
++  return torrent::c_sa_unique_ptr(sa.release());
++}
++
++//
++// Address info tests:
++//
++
++typedef std::function<int (torrent::ai_unique_ptr&)> test_ai_ref;
++
++enum ai_flags_enum : int {
++      aif_none = 0x0,
++      aif_inet = 0x1,
++      aif_inet6 = 0x2,
++      aif_any = 0x4,
++};
++
++constexpr ai_flags_enum operator | (ai_flags_enum a, ai_flags_enum b) {
++  return static_cast<ai_flags_enum>(static_cast<int>(a) | static_cast<int>(b));
++}
++
++template <ai_flags_enum ai_flags>
++inline bool
++test_valid_ai_ref(test_ai_ref ftor, uint16_t port = 0) {
++  torrent::ai_unique_ptr ai;
++
++  if (int err = ftor(ai)) {
++    std::cout << std::endl << "valid_ai_ref got error '" << gai_strerror(err) << "'" << std::endl;
++    return false;
++  }
++
++  if ((ai_flags & aif_inet) && !torrent::sa_is_inet(ai->ai_addr))
++    return false;
++
++  if ((ai_flags & aif_inet6) && !torrent::sa_is_inet6(ai->ai_addr))
++    return false;
++
++  if (!!(ai_flags & aif_any) == !torrent::sa_is_any(ai->ai_addr))
++    return false;
++
++  if (torrent::sa_port(ai->ai_addr) != port)
++    return false;
++
++  return true;
++}
++
++inline bool
++test_valid_ai_ref_err(test_ai_ref ftor, int expect_err) {
++  torrent::ai_unique_ptr ai;
++  int err = ftor(ai);
++
++  if (err != expect_err) {
++    std::cout << std::endl << "ai_ref_err got wrong error, expected '" << gai_strerror(expect_err) << "', got '" << gai_strerror(err) << "'" << std::endl;
++    return false;
++  }
++
++  return true;
++}
++
++#endif
+diff --git a/test/helpers/progress_listener.cc b/test/helpers/progress_listener.cc
+new file mode 100644
+index 00000000..02803ffc
+--- /dev/null
++++ b/test/helpers/progress_listener.cc
+@@ -0,0 +1,63 @@
++#include "config.h"
++
++#include "progress_listener.h"
++
++#include <algorithm>
++#include <iostream>
++#include <iterator>
++#include <numeric>
++#include <stdexcept>
++#include "torrent/utils/log.h"
++#include "torrent/utils/log_buffer.h"
++
++static std::string
++get_test_path(const test_list_type& tl) {
++  if (tl.size() < 2)
++    return "";
++
++  return std::accumulate(std::next(tl.begin()), std::prev(tl.end()), std::string(), [](std::string result, CppUnit::Test* test) {
++      return std::move(result) + test->getName() + "::";
++    });
++}
++
++void
++progress_listener::startTest(CppUnit::Test *test) {
++  std::cout << get_test_path(m_test_path) << test->getName() << std::flush;
++
++  torrent::log_cleanup();
++
++  m_last_test_failed = false;
++  m_current_log_buffer = torrent::log_open_log_buffer("test_output");
++}
++
++void
++progress_listener::addFailure(const CppUnit::TestFailure &failure) {
++  // AddFailure is called for parent test suits, so only deal with leafs.
++  if (m_current_log_buffer == nullptr)
++    return;
++
++  std::cout << " : " << (failure.isError() ? "error" : "assertion");
++
++  m_last_test_failed = true;
++  m_failures.push_back(std::move(failure_type{failure.failedTestName(), std::move(m_current_log_buffer)}));
++}
++
++void
++progress_listener::endTest(CppUnit::Test *test) {
++  std::cout << (m_last_test_failed ? "" : " : OK") << std::endl;
++
++  m_current_log_buffer.reset();
++  torrent::log_cleanup();
++}
++
++void
++progress_listener::startSuite(CppUnit::Test *suite) {
++  m_test_path.push_back(suite);
++
++  std::cout << std::endl << get_test_path(m_test_path) << suite->getName() << ":" << std::endl;
++}
++
++void
++progress_listener::endSuite(CppUnit::Test *suite) {
++  m_test_path.pop_back();
++}
+diff --git a/test/helpers/progress_listener.h b/test/helpers/progress_listener.h
+new file mode 100644
+index 00000000..18fb8faa
+--- /dev/null
++++ b/test/helpers/progress_listener.h
+@@ -0,0 +1,47 @@
++#include <memory>
++#include <vector>
++#include <cppunit/Test.h>
++#include <cppunit/TestFailure.h>
++#include <cppunit/TestListener.h>
++
++#include "torrent/utils/log_buffer.h"
++
++struct failure_type {
++  std::string name;
++  torrent::log_buffer_ptr log;
++};
++
++typedef std::unique_ptr<CppUnit::TestFailure> test_failure_ptr;
++typedef std::vector<CppUnit::Test*> test_list_type;
++typedef std::vector<failure_type> failure_list_type;
++
++class progress_listener : public CppUnit::TestListener {
++public:
++  progress_listener() : m_last_test_failed(false) {}
++
++  void startTest(CppUnit::Test *test) override;
++  void addFailure(const CppUnit::TestFailure &failure) override;
++  void endTest(CppUnit::Test *test) override;
++
++  void startSuite(CppUnit::Test *suite) override;
++  void endSuite(CppUnit::Test *suite) override;
++
++  //Called by a TestRunner before running the test.
++  // void startTestRun(CppUnit::Test *test, CppUnit::TestResult *event_manager) override;
++
++  // Called by a TestRunner after running the test.
++  // void endTestRun(CppUnit::Test *test, CppUnit::TestResult *event_manager) override;
++
++  const failure_list_type& failures() { return m_failures; }
++  failure_list_type&& move_failures() { return std::move(m_failures); }
++
++private:
++  progress_listener(const progress_listener& rhs) = delete;
++  void operator =(const progress_listener& rhs) = delete;
++
++  test_list_type    m_test_path;
++  failure_list_type m_failures;
++  bool              m_last_test_failed;
++
++  torrent::log_buffer_ptr m_current_log_buffer;
++};
+diff --git a/test/helpers/test_fixture.cc b/test/helpers/test_fixture.cc
+new file mode 100644
+index 00000000..4d8d7214
+--- /dev/null
++++ b/test/helpers/test_fixture.cc
+@@ -0,0 +1,18 @@
++#include "config.h"
++
++#include "test_fixture.h"
++
++#include "torrent/utils/log.h"
++
++void
++test_fixture::setUp() {
++  mock_init();
++
++  log_add_group_output(torrent::LOG_CONNECTION_BIND, "test_output");
++  log_add_group_output(torrent::LOG_CONNECTION_FD, "test_output");
++}
++
++void
++test_fixture::tearDown() {
++  mock_cleanup();
++}
+diff --git a/test/helpers/test_fixture.h b/test/helpers/test_fixture.h
+new file mode 100644
+index 00000000..312d5009
+--- /dev/null
++++ b/test/helpers/test_fixture.h
+@@ -0,0 +1,14 @@
++#ifndef LIBTORRENT_HELPER_TEST_FIXTURE_H
++#define LIBTORRENT_HELPER_TEST_FIXTURE_H
++
++#include <cppunit/extensions/HelperMacros.h>
++
++#include "helpers/mock_function.h"
++
++class test_fixture : public CppUnit::TestFixture {
++public:
++  void setUp();
++  void tearDown();
++};
++
++#endif
+diff --git a/test/helpers/utils.h b/test/helpers/utils.h
+new file mode 100644
+index 00000000..d18450c1
+--- /dev/null
++++ b/test/helpers/utils.h
+@@ -0,0 +1,60 @@
++#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 e69d3d70..da93fead 100644
+--- a/test/main.cc
++++ b/test/main.cc
+@@ -1,44 +1,92 @@
++#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>
+ 
+-int main(int argc, char* argv[])
+-{
++#ifdef USE_EXECINFO
++#include <execinfo.h>
++#endif
++
++#include "helpers/progress_listener.h"
++#include "helpers/utils.h"
++
++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("net");
++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent/net");
++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("torrent/utils");
++
++void
++do_test_panic(int signum) {
++  signal(signum, SIG_DFL);
++
++  std::cout << std::endl << std::endl << "Caught " << strsignal(signum) << ", dumping stack:" << std::endl << std::endl;
++  
++#ifdef USE_EXECINFO
++  void* stackPtrs[20];
++
++  // Print the stack and exit.
++  int stackSize = backtrace(stackPtrs, 20);
++  char** stackStrings = backtrace_symbols(stackPtrs, stackSize);
++
++  for (int i = 0; i < stackSize; ++i)
++    std::cout << stackStrings[i] << std::endl;
++
++#else
++  std::cout << "Stack dump not enabled." << std::endl;
++#endif
++
++  std::cout << std::endl;
++  torrent::log_cleanup();
++  std::abort();
++}
++
++void
++register_signal_handlers() {
++  struct sigaction sa;
++  sigemptyset(&sa.sa_mask);
++  sa.sa_flags = SA_RESTART;
++  sa.sa_handler = &do_test_panic;
++
++  if (sigaction(SIGSEGV, &sa, NULL) == -1) {
++    std::cout << "Could not register signal handlers." << std::endl;
++    exit(-1);
++  }
++}
++
++int main(int argc, char* argv[]) {
++  register_signal_handlers();
++
+   CppUnit::TestResult controller;
+   CppUnit::TestResultCollector result;
+-  CppUnit::BriefTestProgressListener progressListener;
++  progress_listener progress;
+ 
+   controller.addListener( &result );        
+-  controller.addListener( &progressListener );
+-
+-  // Get the top level suite from the registry
+-  CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
++  controller.addListener( &progress );
+ 
+-  // Adds the test to the list of test to run
+   CppUnit::TextUi::TestRunner runner;
+-  runner.addTest( suite );
++  add_tests(runner, std::getenv("TEST_NAME"));
+ 
+-  // Change the default outputter to a compiler error format outputter
+-  runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),
+-                                                       std::cerr ) );
+   try {
+     std::cout << "Running ";
+     runner.run( controller );
+  
+-    std::cerr << std::endl;
+- 
++    // TODO: Make outputter.
++    dump_failures(progress.failures());
++
+     // Print test in a compiler compatible format.
+     CppUnit::CompilerOutputter outputter( &result, std::cerr );
+     outputter.write();                      
+ 
+   } catch ( std::invalid_argument &e ) { // Test path not resolved
+-    std::cerr  <<  std::endl  
+-               <<  "ERROR: "  <<  e.what()
+-               << std::endl;
++    std::cerr  <<  std::endl <<  "ERROR: "  <<  e.what() << std::endl;
+     return 1;
+   }
+ 
+diff --git a/test/net/test_socket_listen.cc b/test/net/test_socket_listen.cc
+new file mode 100644
+index 00000000..e86a078b
+--- /dev/null
++++ b/test/net/test_socket_listen.cc
+@@ -0,0 +1,398 @@
++#include "config.h"
++
++#include "test_socket_listen.h"
++
++#include "helpers/expect_fd.h"
++#include "helpers/expect_utils.h"
++#include "helpers/mock_function.h"
++#include "helpers/network.h"
++
++#include <net/socket_listen.h>
++#include <torrent/exceptions.h>
++#include <torrent/utils/log.h>
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_socket_listen, "net");
++
++struct test_sl_deleter {
++  void operator()(torrent::socket_listen* sl) const { if (!sl->is_open()) delete sl; }
++};
++
++typedef std::unique_ptr<torrent::socket_listen, test_sl_deleter> test_sl_unique_ptr;
++
++#define TEST_SL_BEGIN(name)                                     \
++  test_sl_unique_ptr sl(new torrent::socket_listen);            \
++  std::vector<torrent::sa_unique_ptr> sap_cache;                \
++  lt_log_print(torrent::LOG_MOCK_CALLS, "sl_begin: %s", name);  \
++  TEST_DEFAULT_SA;
++
++#define TEST_SL_ASSERT_OPEN(_sap_bind, _sap_result, _flags)             \
++  TEST_SL_ASSERT_OPEN_PORT(_sap_bind, _sap_result, 5000, 5009, 5005, _flags); \
++  CPPUNIT_ASSERT(sl->socket_address_port() == 5005);
++
++#define TEST_SL_ASSERT_OPEN_PORT(_sap_bind, _sap_result, _first_port, _last_port, _itr_port, _flags) \
++  expect_event_open_re(0);                                              \
++  CPPUNIT_ASSERT(sl->open(_sap_bind, _first_port, _last_port, _itr_port, _flags)); \
++  CPPUNIT_ASSERT(sl->is_open());                                        \
++  CPPUNIT_ASSERT(torrent::sa_equal(sl->socket_address(), _sap_result.get()));
++
++#define TEST_SL_ASSERT_OPEN_SEQUENTIAL(_sap_bind, _sap_result, _first_port, _last_port, _flags) \
++  expect_event_open_re(0);                                              \
++  CPPUNIT_ASSERT(sl->open_sequential(_sap_bind, _first_port, _last_port, _flags)); \
++  CPPUNIT_ASSERT(sl->is_open());                                        \
++  CPPUNIT_ASSERT(torrent::sa_equal(sl->socket_address(), _sap_result.get()));
++
++#define TEST_SL_ASSERT_OPEN_RANDOMIZE(_sap_bind, _sap_result, _first_port, _last_port, _flags) \
++  expect_event_open_re(0);                                              \
++  CPPUNIT_ASSERT(sl->open_randomize(_sap_bind, _first_port, _last_port, _flags)); \
++  CPPUNIT_ASSERT(sl->is_open());                                        \
++  CPPUNIT_ASSERT(torrent::sa_equal(sl->socket_address(), _sap_result.get()));
++
++#define TEST_SL_ASSERT_CLOSED()                           \
++  CPPUNIT_ASSERT(!sl->is_open());                         \
++  CPPUNIT_ASSERT(sl->file_descriptor() == -1);            \
++  CPPUNIT_ASSERT(sl->socket_address() == nullptr);        \
++  CPPUNIT_ASSERT(sl->socket_address_port() == 0);
++
++#define TEST_SL_CLOSE(_fd)                                              \
++  mock_expect(&torrent::fd__close, 0, _fd);                             \
++  mock_expect(&torrent::poll_event_closed, (torrent::Event*)sl.get());  \
++  CPPUNIT_ASSERT_NO_THROW(sl->close());                                 \
++  TEST_SL_ASSERT_CLOSED();
++
++#define TEST_SL_MOCK_CLOSED_PORT_RANGE(_src_sap, _first_port, _last_port) \
++  { uint16_t _port = _first_port; do {                                  \
++      sap_cache.push_back(torrent::sap_copy(_src_sap));                 \
++      torrent::sap_set_port(sap_cache.back(), _port);                   \
++      mock_expect(&torrent::fd__bind, -1, 1000,                         \
++                  (const sockaddr*)sap_cache.back().get(),              \
++                  (socklen_t)torrent::sap_length(sap_cache.back()));    \
++    } while (_port++ != _last_port);                                    \
++  }
++
++void
++test_socket_listen::test_basic() {
++  TEST_SL_BEGIN("basic");
++  TEST_SL_ASSERT_CLOSED();
++  CPPUNIT_ASSERT(sl->backlog() == SOMAXCONN);
++  CPPUNIT_ASSERT(sl->type_name() == std::string("socket_listen"));
++}
++
++void
++test_socket_listen::test_open_error() {
++  { TEST_SL_BEGIN("open twice");
++    expect_fd_inet6_tcp_nonblock(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream | torrent::fd_flag_nonblock);
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5000, 5009, 5005, torrent::fd_flag_stream),
++                         torrent::internal_error);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_any, stream, no v4only");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin_any), 5000, 5009, 5005, torrent::fd_flag_stream),
++                         torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++}
++
++void
++test_socket_listen::test_open_sap() {
++  { TEST_SL_BEGIN("sin6_any, stream");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_any, stream|v4only");
++    expect_fd_inet_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin_any), c_sin_any_5005, torrent::fd_flag_stream | torrent::fd_flag_v4only);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_1, stream|v4only");
++    expect_fd_inet_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin_1_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin_1), c_sin_1_5005, torrent::fd_flag_stream | torrent::fd_flag_v4only);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream|v6only");
++    expect_fd_inet6_tcp(1000);
++    mock_expect(&torrent::fd__setsockopt_int, 0, 1000, (int)IPPROTO_IPV6, (int)IPV6_V6ONLY, (int)true);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream | torrent::fd_flag_v6only);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_1, stream|v6only");
++    expect_fd_inet6_tcp(1000);
++    mock_expect(&torrent::fd__setsockopt_int, 0, 1000, (int)IPPROTO_IPV6, (int)IPV6_V6ONLY, (int)true);
++    expect_fd_bind_listen(1000, c_sin6_1_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_1), c_sin6_1_5005, torrent::fd_flag_stream | torrent::fd_flag_v6only);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++void
++test_socket_listen::test_open_sap_error() {
++  { TEST_SL_BEGIN("unspec");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sa_make_unspec(), 5000, 5009, 5005, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("unix");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sa_make_unix("test"), 5000, 5009, 5005, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin_any_5005");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin_any_5005), 5000, 5009, 5005, torrent::fd_flag_stream | torrent::fd_flag_v4only), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any_5005");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any_5005), 5000, 5009, 5005, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin_any");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_to_v4mapped(sin_any), 5000, 5009, 5005, torrent::fd_flag_stream | torrent::fd_flag_v4only), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin_1, v4mapped");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_to_v4mapped(sin_1), 5000, 5009, 5005, torrent::fd_flag_stream | torrent::fd_flag_v4only), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin_broadcast");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin_bc), 5000, 5009, 5005, torrent::fd_flag_stream | torrent::fd_flag_v4only), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++}
++
++void
++test_socket_listen::test_open_flags() {
++  { TEST_SL_BEGIN("sin_any, stream|v4only|nonblock");
++    expect_fd_inet_tcp_nonblock(1000);
++    expect_fd_bind_listen(1000, c_sin_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy_addr(sin_any), c_sin_any_5005, torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_nonblock);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream|nonblock");
++    expect_fd_inet6_tcp_nonblock(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream | torrent::fd_flag_nonblock);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_any, stream|v4only|reuse_address");
++    expect_fd_inet_tcp(1000);
++    mock_expect(&torrent::fd__setsockopt_int, 0, 1000, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++    expect_fd_bind_listen(1000, c_sin_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy_addr(sin_any), c_sin_any_5005, torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_reuse_address);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream|reuse_address");
++    expect_fd_inet6_tcp(1000);
++    mock_expect(&torrent::fd__setsockopt_int, 0, 1000, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream | torrent::fd_flag_reuse_address);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_any, stream|v4only|nonblock|reuse_address");
++    expect_fd_inet_tcp_nonblock(1000);
++    mock_expect(&torrent::fd__setsockopt_int, 0, 1000, (int)SOL_SOCKET, (int)SO_REUSEADDR, (int)true);
++    expect_fd_bind_listen(1000, c_sin_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy_addr(sin_any), c_sin_any_5005, torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream|nonblock|reuse_address");
++    expect_fd_inet6_tcp_nonblock_reuseaddr(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN(torrent::sap_copy(sin6_any), c_sin6_any_5005, torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++void
++test_socket_listen::test_open_flags_error() {
++  { TEST_SL_BEGIN("sin6_any, fd_flags(0)");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5000, 5009, 5005, torrent::fd_flags(0)), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, fd_flags(0xffff)");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5000, 5009, 5005, torrent::fd_flags(0xffff)), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++}
++
++void
++test_socket_listen::test_open_port_single() {
++  { TEST_SL_BEGIN("sin6_any, stream");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5000);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5000, 5000, 5000, 5000, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin_any, stream");
++    expect_fd_inet_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin_any_5000);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin_any), c_sin_any_5000, 5000, 5000, 5000, torrent::fd_flag_stream | torrent::fd_flag_v4only);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++void
++test_socket_listen::test_open_port_single_error() {
++  { TEST_SL_BEGIN("sin6_any, 0, 0, 0");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0, 0, 0, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, 1000, 0, 0");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 1000, 0, 0, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, 0, 1000, 0");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0, 1000, 0, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, 0, 0, 500");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0, 0, 500, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, 0, 1000, 500");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0, 1000, 500, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++}
++
++void
++test_socket_listen::test_open_port_range() {
++  { TEST_SL_BEGIN("sin6_any, stream, first");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5000);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5000, 5000, 5010, 5000, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, from first to middle port");
++    expect_fd_inet6_tcp(1000);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5000, 5004);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5005, 5000, 5010, 5000, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, from first to last port");
++    expect_fd_inet6_tcp(1000);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5000, 5009);
++    expect_fd_bind_listen(1000, c_sin6_any_5010);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5010, 5000, 5010, 5000, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, middle");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5005, 5000, 5010, 5005, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, from middle to last port");
++    expect_fd_inet6_tcp(1000);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5005, 5009);
++    expect_fd_bind_listen(1000, c_sin6_any_5010);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5010, 5000, 5010, 5005, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, last");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5010);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5010, 5000, 5010, 5010, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, from last to first port");
++    expect_fd_inet6_tcp(1000);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5010, 5010);
++    expect_fd_bind_listen(1000, c_sin6_any_5000);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5000, 5000, 5010, 5010, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++  { TEST_SL_BEGIN("sin6_any, stream, from last to middle port");
++    expect_fd_inet6_tcp(1000);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5010, 5010);
++    TEST_SL_MOCK_CLOSED_PORT_RANGE(sin6_any, 5000, 5004);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN_PORT(torrent::sap_copy(sin6_any), c_sin6_any_5005, 5000, 5010, 5010, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++void
++test_socket_listen::test_open_port_range_error() {
++  { TEST_SL_BEGIN("sin6_any, first > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5000, 4999, 5000, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, first > itr");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5001, 5009, 5000, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, itr > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 5000, 5009, 5010, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, min first > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 2, 1, 2, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, min first > itr");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 2, 1000, 1, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, min itr > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 1, 2, 3, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, max first > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0xffff, 0xfffe, 0xffff, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, max first > itr");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0xffff, 0xffff, 0xfffe, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++  { TEST_SL_BEGIN("sin6_any, max itr > last");
++    CPPUNIT_ASSERT_THROW(sl->open(torrent::sap_copy(sin6_any), 0xfffe, 0xfffe, 0xffff, torrent::fd_flag_stream), torrent::internal_error);
++    TEST_SL_ASSERT_CLOSED();
++  };
++}
++
++void
++test_socket_listen::test_open_sequential() {
++  { TEST_SL_BEGIN("sin6_any, stream");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5000);
++    TEST_SL_ASSERT_OPEN_SEQUENTIAL(torrent::sap_copy(sin6_any), c_sin6_any_5000, 5000, 5010, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++void
++test_socket_listen::test_open_randomize() {
++  { TEST_SL_BEGIN("sin6_any, stream");
++    expect_random_uniform_uint16(5005, 5000, 5010);
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5005);
++    TEST_SL_ASSERT_OPEN_RANDOMIZE(torrent::sap_copy(sin6_any), c_sin6_any_5005, 5000, 5010, torrent::fd_flag_stream);
++    TEST_SL_CLOSE(1000);
++  };
++}
++
++// deal with reuse error
++
++void
++test_socket_listen::test_accept() {
++  { TEST_SL_BEGIN("sin6_any, stream");
++    expect_fd_inet6_tcp(1000);
++    expect_fd_bind_listen(1000, c_sin6_any_5000);
++    TEST_SL_ASSERT_OPEN_SEQUENTIAL(torrent::sap_copy(sin6_any), c_sin6_any_5000, 5000, 5010, torrent::fd_flag_stream);
++
++    std::vector<torrent::fd_sap_tuple> accepted_connections;
++
++    sl->set_slot_accepted([&accepted_connections](int accept_fd, torrent::sa_unique_ptr sap) {
++        accepted_connections.push_back(torrent::fd_sap_tuple{accept_fd, std::move(sap)});
++      });
++
++    // CPPUNIT_ASSERT(accepted_connections.size() > 0 && torrent::fd_sap_equal(accepted_connections[0], torrent::fd_sap_tuple{2000, torrent::sap_copy(sin6_1_5100)}));
++
++    TEST_SL_CLOSE(1000);
++  };
++}
+diff --git a/test/net/test_socket_listen.h b/test/net/test_socket_listen.h
+new file mode 100644
+index 00000000..5d06f7f3
+--- /dev/null
++++ b/test/net/test_socket_listen.h
+@@ -0,0 +1,44 @@
++#include "helpers/test_fixture.h"
++
++class test_socket_listen : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_socket_listen);
++
++  CPPUNIT_TEST(test_basic);
++
++  CPPUNIT_TEST(test_open_error);
++  CPPUNIT_TEST(test_open_sap);
++  CPPUNIT_TEST(test_open_sap_error);
++  CPPUNIT_TEST(test_open_flags);
++  CPPUNIT_TEST(test_open_flags_error);
++
++  CPPUNIT_TEST(test_open_port_single);
++  CPPUNIT_TEST(test_open_port_single_error);
++  CPPUNIT_TEST(test_open_port_range);
++  CPPUNIT_TEST(test_open_port_range_error);
++
++  CPPUNIT_TEST(test_open_sequential);
++  CPPUNIT_TEST(test_open_randomize);
++
++  CPPUNIT_TEST(test_accept);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void test_basic();
++
++  void test_open_error();
++  void test_open_sap();
++  void test_open_sap_error();
++  void test_open_flags();
++  void test_open_flags_error();
++
++  void test_open_port_single();
++  void test_open_port_single_error();
++  void test_open_port_range();
++  void test_open_port_range_error();
++
++  void test_open_sequential();
++  void test_open_randomize();
++
++  void test_accept();
++};
+diff --git a/test/torrent/net/test_address_info.cc b/test/torrent/net/test_address_info.cc
+new file mode 100644
+index 00000000..e3ee24d1
+--- /dev/null
++++ b/test/torrent/net/test_address_info.cc
+@@ -0,0 +1,62 @@
++#include "config.h"
++
++#include "test_address_info.h"
++
++#include "helpers/network.h"
++#include "torrent/net/address_info.h"
++#include "torrent/net/socket_address.h"
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_address_info, "torrent/net");
++
++void
++test_address_info::test_basic() {
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet|aif_any> (std::bind(torrent::ai_get_addrinfo, "0.0.0.0", nullptr, nullptr, std::placeholders::_1)));
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet6|aif_any>(std::bind(torrent::ai_get_addrinfo, "::", nullptr, nullptr, std::placeholders::_1)));
++
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet> (std::bind(torrent::ai_get_addrinfo, "1.1.1.1", nullptr, nullptr, std::placeholders::_1)));
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet6>(std::bind(torrent::ai_get_addrinfo, "ff01::1", nullptr, nullptr, std::placeholders::_1)));
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet6>(std::bind(torrent::ai_get_addrinfo, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", nullptr, nullptr, std::placeholders::_1)));
++
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet> (std::bind(torrent::ai_get_addrinfo, "1.1.1.1", "22123", nullptr, std::placeholders::_1), 22123));
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet6>(std::bind(torrent::ai_get_addrinfo, "2001:db8:a::", "22123", nullptr, std::placeholders::_1), 22123));
++
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_none> (std::bind(torrent::ai_get_addrinfo, "localhost", nullptr, nullptr, std::placeholders::_1)));
++
++  CPPUNIT_ASSERT(test_valid_ai_ref_err(std::bind(torrent::ai_get_addrinfo, "1.1.1.300", nullptr, nullptr, std::placeholders::_1), EAI_NONAME));
++  CPPUNIT_ASSERT(test_valid_ai_ref_err(std::bind(torrent::ai_get_addrinfo, "2001:db8:a::22123", nullptr, nullptr, std::placeholders::_1), EAI_NONAME));
++}
++
++void
++test_address_info::test_numericserv() {
++  CPPUNIT_ASSERT(test_valid_ai_ref<aif_inet> (std::bind(torrent::ai_get_addrinfo, "1.1.1.1", nullptr, torrent::ai_make_hint(AI_NUMERICHOST, 0, 0).get(), std::placeholders::_1)));
++
++  CPPUNIT_ASSERT(test_valid_ai_ref_err(std::bind(torrent::ai_get_addrinfo, "localhost", nullptr, torrent::ai_make_hint(AI_NUMERICHOST, 0, 0).get(), std::placeholders::_1), EAI_NONAME));
++}
++
++void
++test_address_info::test_helpers() {
++  torrent::sin_unique_ptr sin_zero = torrent::sin_from_sa(wrap_ai_get_first_sa("0.0.0.0"));
++  CPPUNIT_ASSERT(sin_zero != nullptr);
++  CPPUNIT_ASSERT(sin_zero->sin_family == AF_INET);
++  CPPUNIT_ASSERT(sin_zero->sin_port == 0);
++  CPPUNIT_ASSERT(sin_zero->sin_addr.s_addr == in_addr().s_addr);
++
++  torrent::sin_unique_ptr sin_1 = torrent::sin_from_sa(wrap_ai_get_first_sa("1.2.3.4"));
++  CPPUNIT_ASSERT(sin_1 != nullptr);
++  CPPUNIT_ASSERT(sin_1->sin_family == AF_INET);
++  CPPUNIT_ASSERT(sin_1->sin_port == 0);
++  CPPUNIT_ASSERT(sin_1->sin_addr.s_addr == htonl(0x01020304));
++
++  torrent::sin6_unique_ptr sin6_zero = torrent::sin6_from_sa(wrap_ai_get_first_sa("::"));
++  CPPUNIT_ASSERT(sin6_zero != nullptr);
++  CPPUNIT_ASSERT(sin6_zero->sin6_family == AF_INET6);
++  CPPUNIT_ASSERT(sin6_zero->sin6_port == 0);
++  CPPUNIT_ASSERT(compare_sin6_addr(sin6_zero->sin6_addr, in6_addr{0}));
++
++  torrent::sin6_unique_ptr sin6_1 = torrent::sin6_from_sa(wrap_ai_get_first_sa("ff01::1"));
++  CPPUNIT_ASSERT(sin6_1 != nullptr);
++  CPPUNIT_ASSERT(sin6_1->sin6_family == AF_INET6);
++  CPPUNIT_ASSERT(sin6_1->sin6_port == 0);
++  CPPUNIT_ASSERT(compare_sin6_addr(sin6_1->sin6_addr, in6_addr{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}));
++  CPPUNIT_ASSERT(!compare_sin6_addr(sin6_1->sin6_addr, in6_addr{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}));
++}
+diff --git a/test/torrent/net/test_address_info.h b/test/torrent/net/test_address_info.h
+new file mode 100644
+index 00000000..c2ce9188
+--- /dev/null
++++ b/test/torrent/net/test_address_info.h
+@@ -0,0 +1,19 @@
++#include <cppunit/extensions/HelperMacros.h>
++
++class test_address_info : public CppUnit::TestFixture {
++  CPPUNIT_TEST_SUITE(test_address_info);
++
++  CPPUNIT_TEST(test_basic);
++  CPPUNIT_TEST(test_numericserv);
++  CPPUNIT_TEST(test_helpers);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void setUp() {}
++  void tearDown() {}
++
++  void test_basic();
++  void test_numericserv();
++  void test_helpers();
++};
+diff --git a/test/torrent/net/test_fd.cc b/test/torrent/net/test_fd.cc
+new file mode 100644
+index 00000000..3cab0c5e
+--- /dev/null
++++ b/test/torrent/net/test_fd.cc
+@@ -0,0 +1,24 @@
++#include "config.h"
++
++#include "test_fd.h"
++
++#include <torrent/net/fd.h>
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_fd, "torrent/net");
++
++void
++test_fd::test_valid_flags() {
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_nonblock));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_reuse_address));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v6only));
++
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_v4only | torrent::fd_flag_v6only));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_v6only));
++
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags()));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(~torrent::fd_flag_all)));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(torrent::fd_flag_stream | ~torrent::fd_flag_all)));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(0x3245132)));
++}
+diff --git a/test/torrent/net/test_fd.h b/test/torrent/net/test_fd.h
+new file mode 100644
+index 00000000..6ba718fc
+--- /dev/null
++++ b/test/torrent/net/test_fd.h
+@@ -0,0 +1,12 @@
++#include "helpers/test_fixture.h"
++
++class test_fd : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_fd);
++
++  CPPUNIT_TEST(test_valid_flags);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void test_valid_flags();
++};
+diff --git a/test/torrent/net/test_socket_address.cc b/test/torrent/net/test_socket_address.cc
+new file mode 100644
+index 00000000..8a1b0c8a
+--- /dev/null
++++ b/test/torrent/net/test_socket_address.cc
+@@ -0,0 +1,383 @@
++#include "config.h"
++
++#include "test_socket_address.h"
++
++#include "helpers/network.h"
++#include "torrent/exceptions.h"
++#include "torrent/net/socket_address.h"
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_socket_address, "torrent/net");
++
++void
++test_socket_address::test_sa_is_any() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_is_any(sin_any));
++  CPPUNIT_ASSERT(torrent::sap_is_any(sin_any_5000));
++  CPPUNIT_ASSERT(torrent::sap_is_any(sin6_v4_any));
++  CPPUNIT_ASSERT(torrent::sap_is_any(sin6_v4_any_5000));
++
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin_bc));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin6_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin_bc_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin_1_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(sin6_1_5000));
++
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin_bc));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin6_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin_bc_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin_1_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_any(c_sin6_1_5000));
++}
++
++void
++test_socket_address::test_sa_is_broadcast() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_is_broadcast(sin_bc));
++  CPPUNIT_ASSERT(torrent::sap_is_broadcast(sin_bc_5000));
++  CPPUNIT_ASSERT(torrent::sap_is_broadcast(sin6_v4_bc));
++  CPPUNIT_ASSERT(torrent::sap_is_broadcast(sin6_v4_bc_5000));
++
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin_any));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin6_any));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin6_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin_any_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin_1_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin6_any_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(sin6_1_5000));
++
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin_any));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin6_any));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin6_1));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin_any_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin_1_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin6_any_5000));
++  CPPUNIT_ASSERT(!torrent::sap_is_broadcast(c_sin6_1_5000));
++}
++
++void
++test_socket_address::test_make() {
++  torrent::sa_unique_ptr sa_unspec = torrent::sa_make_unspec();
++  CPPUNIT_ASSERT(sa_unspec != nullptr);
++  CPPUNIT_ASSERT(sa_unspec->sa_family == AF_UNSPEC);
++
++  torrent::sa_unique_ptr sa_inet = torrent::sa_make_inet();
++  CPPUNIT_ASSERT(sa_inet != nullptr);
++  CPPUNIT_ASSERT(sa_inet->sa_family == AF_INET);
++
++  sockaddr_in* sin_inet = reinterpret_cast<sockaddr_in*>(sa_inet.get());
++  CPPUNIT_ASSERT(sin_inet->sin_family == AF_INET);
++  CPPUNIT_ASSERT(sin_inet->sin_port == 0);
++  CPPUNIT_ASSERT(sin_inet->sin_addr.s_addr == in_addr().s_addr);
++
++  torrent::sa_unique_ptr sa_inet6 = torrent::sa_make_inet6();
++  CPPUNIT_ASSERT(sa_inet6 != nullptr);
++  CPPUNIT_ASSERT(sa_inet6->sa_family == AF_INET6);
++
++  sockaddr_in6* sin6_inet6 = reinterpret_cast<sockaddr_in6*>(sa_inet6.get());
++  CPPUNIT_ASSERT(sin6_inet6->sin6_family == AF_INET6);
++  CPPUNIT_ASSERT(sin6_inet6->sin6_port == 0);
++  CPPUNIT_ASSERT(sin6_inet6->sin6_flowinfo == 0);
++  CPPUNIT_ASSERT(compare_sin6_addr(sin6_inet6->sin6_addr, in6_addr{0}));
++  CPPUNIT_ASSERT(sin6_inet6->sin6_scope_id == 0);
++
++  torrent::sa_unique_ptr sa_unix = torrent::sa_make_unix("");
++  CPPUNIT_ASSERT(sa_unix != nullptr);
++  CPPUNIT_ASSERT(sa_unix->sa_family == AF_UNIX);
++}
++
++void
++test_socket_address::test_sin_from_sa() {
++  torrent::sa_unique_ptr sa_zero = wrap_ai_get_first_sa("0.0.0.0");
++  torrent::sin_unique_ptr sin_zero;
++
++  CPPUNIT_ASSERT(sa_zero != nullptr);
++  CPPUNIT_ASSERT_NO_THROW({ sin_zero = torrent::sin_from_sa(std::move(sa_zero)); });
++  CPPUNIT_ASSERT(sa_zero == nullptr);
++  CPPUNIT_ASSERT(sin_zero != nullptr);
++
++  CPPUNIT_ASSERT(sin_zero->sin_addr.s_addr == htonl(0x0));
++
++  torrent::sa_unique_ptr sa_inet = wrap_ai_get_first_sa("1.2.3.4");
++  torrent::sin_unique_ptr sin_inet;
++
++  CPPUNIT_ASSERT(sa_inet != nullptr);
++  CPPUNIT_ASSERT_NO_THROW({ sin_inet = torrent::sin_from_sa(std::move(sa_inet)); });
++  CPPUNIT_ASSERT(sa_inet == nullptr);
++  CPPUNIT_ASSERT(sin_inet != nullptr);
++
++  CPPUNIT_ASSERT(sin_inet->sin_addr.s_addr == htonl(0x01020304));
++  
++  CPPUNIT_ASSERT_THROW(torrent::sin_from_sa(torrent::sa_unique_ptr()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sin_from_sa(torrent::sa_make_unspec()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sin_from_sa(torrent::sa_make_inet6()), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sin6_from_sa() {
++  torrent::sa_unique_ptr sa_zero = wrap_ai_get_first_sa("::");
++  torrent::sin6_unique_ptr sin6_zero;
++
++  CPPUNIT_ASSERT(sa_zero != nullptr);
++  CPPUNIT_ASSERT_NO_THROW({ sin6_zero = torrent::sin6_from_sa(std::move(sa_zero)); });
++  CPPUNIT_ASSERT(sa_zero == nullptr);
++  CPPUNIT_ASSERT(sin6_zero != nullptr);
++
++  CPPUNIT_ASSERT(sin6_zero->sin6_addr.s6_addr[0] == 0x0);
++  CPPUNIT_ASSERT(sin6_zero->sin6_addr.s6_addr[1] == 0x0);
++  CPPUNIT_ASSERT(sin6_zero->sin6_addr.s6_addr[15] == 0x0);
++
++  torrent::sa_unique_ptr sa_inet6 = wrap_ai_get_first_sa("ff01::1");
++  torrent::sin6_unique_ptr sin6_inet6;
++
++  CPPUNIT_ASSERT(sa_inet6 != nullptr);
++  CPPUNIT_ASSERT_NO_THROW({ sin6_inet6 = torrent::sin6_from_sa(std::move(sa_inet6)); });
++  CPPUNIT_ASSERT(sa_inet6 == nullptr);
++  CPPUNIT_ASSERT(sin6_inet6 != nullptr);
++  
++  CPPUNIT_ASSERT(sin6_inet6->sin6_addr.s6_addr[0] == 0xff);
++  CPPUNIT_ASSERT(sin6_inet6->sin6_addr.s6_addr[1] == 0x01);
++  CPPUNIT_ASSERT(sin6_inet6->sin6_addr.s6_addr[15] == 0x01);
++
++  CPPUNIT_ASSERT_THROW(torrent::sin6_from_sa(torrent::sa_unique_ptr()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sin6_from_sa(torrent::sa_make_unspec()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sin6_from_sa(torrent::sa_make_inet()), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_equal() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sa_make_unspec(), torrent::sa_make_unspec()));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sa_make_inet(), torrent::sa_make_inet()));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sa_make_inet6(), torrent::sa_make_inet6()));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal(torrent::sa_make_unspec(), torrent::sa_make_inet()));
++  CPPUNIT_ASSERT(!torrent::sap_equal(torrent::sa_make_unspec(), torrent::sa_make_inet6()));
++  CPPUNIT_ASSERT(!torrent::sap_equal(torrent::sa_make_inet(), torrent::sa_make_inet6()));
++  CPPUNIT_ASSERT(!torrent::sap_equal(torrent::sa_make_inet6(), torrent::sa_make_inet()));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(sin_1, sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(sin_1, c_sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(c_sin_1, sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(c_sin_1, c_sin_1));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin_1, sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin_1, c_sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(c_sin_1, sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(c_sin_1, c_sin_2));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(sin6_1, sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(sin6_1, c_sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(c_sin6_1, sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(c_sin6_1, c_sin6_1));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin6_1, sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin6_1, c_sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(c_sin6_1, sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal(c_sin6_1, c_sin6_2));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(sin_1_5000, sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(sin6_1_5000, sin6_1_5000));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin_1_5000, sin_1_5100));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin6_1_5000, sin6_1_5100));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin_1_5000, sin_2_5000));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin6_1_5000, sin6_2_5000));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin_1_5000, sin_2_5100));
++  CPPUNIT_ASSERT(!torrent::sap_equal(sin6_1_5000, sin6_2_5100));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal(torrent::sa_make_unix(""), torrent::sa_make_unix("")), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal(torrent::sa_make_unix(""), sin6_1), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal(sin6_1, torrent::sa_make_unix("")), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_equal_addr() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sa_make_unspec(), torrent::sa_make_unspec()));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sa_make_inet(), torrent::sa_make_inet()));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sa_make_inet6(), torrent::sa_make_inet6()));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(torrent::sa_make_unspec(), torrent::sa_make_inet()));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(torrent::sa_make_unspec(), torrent::sa_make_inet6()));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(torrent::sa_make_inet(), torrent::sa_make_inet6()));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(torrent::sa_make_inet6(), torrent::sa_make_inet()));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin_1, sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin_1, c_sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(c_sin_1, sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(c_sin_1, c_sin_1));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin_1, sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin_1, c_sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(c_sin_1, sin_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(c_sin_1, c_sin_2));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin6_1, sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin6_1, c_sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(c_sin6_1, sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(c_sin6_1, c_sin6_1));
++
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin6_1, sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin6_1, c_sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(c_sin6_1, sin6_2));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(c_sin6_1, c_sin6_2));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin_1_5000, sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin6_1_5000, sin6_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin_1_5000, sin_1_5100));
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(sin6_1_5000, sin6_1_5100));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin_1_5000, sin_2_5000));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin6_1_5000, sin6_2_5000));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin_1_5000, sin_2_5100));
++  CPPUNIT_ASSERT(!torrent::sap_equal_addr(sin6_1_5000, sin6_2_5100));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal_addr(torrent::sa_make_unix(""), torrent::sa_make_unix("")), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal_addr(torrent::sa_make_unix(""), sin6_1), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_equal_addr(sin6_1, torrent::sa_make_unix("")), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_copy() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(torrent::sa_make_unspec()), torrent::sa_make_unspec()));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(torrent::sa_make_inet()), sin_any));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(torrent::sa_make_inet6()), sin6_any));
++
++  CPPUNIT_ASSERT(torrent::sap_copy(sin_1).get() != sin_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy(c_sin_1).get() != c_sin_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy(sin6_1).get() != sin6_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy(c_sin6_1).get() != c_sin6_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy(sin_1_5000).get() != sin_1_5000.get());
++  CPPUNIT_ASSERT(torrent::sap_copy(sin6_1_5000).get() != sin6_1_5000.get());
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin_1), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin_1), c_sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(c_sin_1), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(c_sin_1), c_sin_1));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin6_1), sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin6_1), c_sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(c_sin6_1), sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(c_sin6_1), c_sin6_1));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin_1_5000), sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin6_1_5000), sin6_1_5000));
++
++  auto sin6_flags = torrent::sap_copy(sin6_1_5000);
++  reinterpret_cast<sockaddr_in6*>(sin6_flags.get())->sin6_flowinfo = 0x12345678;
++  reinterpret_cast<sockaddr_in6*>(sin6_flags.get())->sin6_scope_id = 0x12345678;
++
++  // TODO: Need 'strict' equal test.
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy(sin6_flags), sin6_flags));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy(torrent::sa_unique_ptr()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy(torrent::c_sa_unique_ptr()), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_copy_addr() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_unspec()), torrent::sa_make_unspec()));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_inet()), sin_any));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_inet6()), sin6_any));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_unspec(), 5000), torrent::sa_make_unspec()));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_inet(), 5000), sin_any_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(torrent::sa_make_inet6(), 5000), sin6_any_5000));
++
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(sin_1).get() != sin_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(c_sin_1).get() != c_sin_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(sin6_1).get() != sin6_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(c_sin6_1).get() != c_sin6_1.get());
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(sin_1_5000).get() != sin_1_5000.get());
++  CPPUNIT_ASSERT(torrent::sap_copy_addr(sin6_1_5000).get() != sin6_1_5000.get());
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1), c_sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin_1), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin_1), c_sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1, 5000), sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1, 5000), c_sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin_1, 5000), sin_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin_1, 5000), c_sin_1_5000));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1), sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1), c_sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin6_1), sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin6_1), c_sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1, 5000), sin6_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1, 5000), c_sin6_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin6_1, 5000), sin6_1_5000));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(c_sin6_1, 5000), c_sin6_1_5000));
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1_5000), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1_5000), sin6_1));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin_1_5000, 5100), sin_1_5100));
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_1_5000, 5100), sin6_1_5100));
++
++  auto sin6_flags = wrap_ai_get_first_sa("ff01::1", "5555");
++  reinterpret_cast<sockaddr_in6*>(sin6_flags.get())->sin6_flowinfo = 0x12345678;
++  reinterpret_cast<sockaddr_in6*>(sin6_flags.get())->sin6_scope_id = 0x12345678;
++
++  CPPUNIT_ASSERT(torrent::sap_equal(torrent::sap_copy_addr(sin6_flags), sin6_1));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy_addr(torrent::sa_unique_ptr()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy_addr(torrent::c_sa_unique_ptr()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy_addr(torrent::sa_unique_ptr(), 5000), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_copy_addr(torrent::c_sa_unique_ptr(), 5000), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_from_v4mapped() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_from_v4mapped(sin6_v4_any), sin_any));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_from_v4mapped(sin6_v4_any)));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_from_v4mapped(sin6_v4_1), sin_1));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_from_v4mapped(sin6_v4_1)));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_from_v4mapped(sin6_v4_bc), sin_bc));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_from_v4mapped(sin6_v4_bc)));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(torrent::sa_make_unspec()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(torrent::sa_make_inet()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(torrent::sa_make_unix("")), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(sin_any), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(sin_bc), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_from_v4mapped(sin_1), torrent::internal_error);
++}
++
++void
++test_socket_address::test_sa_to_v4mapped() {
++  TEST_DEFAULT_SA;
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_to_v4mapped(sin_any), sin6_v4_any));
++  CPPUNIT_ASSERT(torrent::sap_is_v4mapped(torrent::sap_to_v4mapped(sin_any)));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_to_v4mapped(sin_any)));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_to_v4mapped(sin_bc), sin6_v4_bc));
++  CPPUNIT_ASSERT(torrent::sap_is_v4mapped(torrent::sap_to_v4mapped(sin_bc)));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_to_v4mapped(sin_bc)));
++
++  CPPUNIT_ASSERT(torrent::sap_equal_addr(torrent::sap_to_v4mapped(sin_1), sin6_v4_1));
++  CPPUNIT_ASSERT(torrent::sap_is_v4mapped(torrent::sap_to_v4mapped(sin_1)));
++  CPPUNIT_ASSERT(torrent::sap_is_port_any(torrent::sap_to_v4mapped(sin_1)));
++
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(torrent::sa_make_unspec()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(torrent::sa_make_inet6()), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(torrent::sa_make_unix("")), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(sin6_any), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(sin6_1), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(sin6_v4_any), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(sin6_v4_bc), torrent::internal_error);
++  CPPUNIT_ASSERT_THROW(torrent::sap_to_v4mapped(sin6_v4_1), torrent::internal_error);
++}
+diff --git a/test/torrent/net/test_socket_address.h b/test/torrent/net/test_socket_address.h
+new file mode 100644
+index 00000000..6157f366
+--- /dev/null
++++ b/test/torrent/net/test_socket_address.h
+@@ -0,0 +1,43 @@
++#include <cppunit/extensions/HelperMacros.h>
++
++class test_socket_address : public CppUnit::TestFixture {
++  CPPUNIT_TEST_SUITE(test_socket_address);
++
++  CPPUNIT_TEST(test_sa_is_any);
++  CPPUNIT_TEST(test_sa_is_broadcast);
++
++  CPPUNIT_TEST(test_make);
++
++  CPPUNIT_TEST(test_sin_from_sa);
++  CPPUNIT_TEST(test_sin6_from_sa);
++
++  CPPUNIT_TEST(test_sa_equal);
++  CPPUNIT_TEST(test_sa_equal_addr);
++  CPPUNIT_TEST(test_sa_copy);
++  CPPUNIT_TEST(test_sa_copy_addr);
++
++  CPPUNIT_TEST(test_sa_from_v4mapped);
++  CPPUNIT_TEST(test_sa_to_v4mapped);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void setUp() {}
++  void tearDown() {}
++
++  void test_sa_is_any();
++  void test_sa_is_broadcast();
++
++  void test_make();
++
++  void test_sin_from_sa();
++  void test_sin6_from_sa();
++
++  void test_sa_equal();
++  void test_sa_equal_addr();
++  void test_sa_copy();
++  void test_sa_copy_addr();
++
++  void test_sa_from_v4mapped();
++  void test_sa_to_v4mapped();
++};
+diff --git a/test/torrent/net/test_socket_address_key.cc b/test/torrent/net/test_socket_address_key.cc
+deleted file mode 100644
+index 7892e730..00000000
+--- a/test/torrent/net/test_socket_address_key.cc
++++ /dev/null
+@@ -1,87 +0,0 @@
+-#include "config.h"
+-
+-#include lt_tr1_functional
+-#include <sys/types.h>
+-#include <sys/socket.h>
+-
+-#include "test_socket_address_key.h"
+-
+-#include "torrent/utils/net.h"
+-#include "torrent/net/socket_address_key.h"
+-
+-CPPUNIT_TEST_SUITE_REGISTRATION(test_socket_address_key);
+-
+-// TODO: Move into a test utilities header:
+-
+-typedef std::function<struct addrinfo* ()> addrinfo_ftor;
+-
+-static torrent::socket_address_key
+-test_create_valid(const char* hostname, addrinfo_ftor ftor) {
+-  struct addrinfo* addr_info;
+-
+-  try {
+-    addr_info = ftor();
+-  } catch (torrent::address_info_error& e) {
+-    CPPUNIT_ASSERT_MESSAGE("Caught address_info_error for '" + std::string(hostname) + "'", false);
+-  }
+-
+-  CPPUNIT_ASSERT_MESSAGE("test_create_valid could not find '" + std::string(hostname) + "'",
+-                         addr_info != NULL);
+-
+-  torrent::socket_address_key sock_key = torrent::socket_address_key::from_sockaddr(addr_info->ai_addr);
+-
+-  CPPUNIT_ASSERT_MESSAGE("test_create_valid failed to create valid socket_address_key for '" + std::string(hostname) + "'",
+-                         sock_key.is_valid());
+-
+-  return sock_key;
+-}
+-
+-static bool
+-test_create_throws(const char* hostname, addrinfo_ftor ftor) {
+-  try {
+-    ftor();
+-
+-    return false;
+-  } catch (torrent::address_info_error& e) {
+-    return true;
+-  }
+-}
+-
+-static torrent::socket_address_key
+-test_create_inet(const char* hostname) {
+-  return test_create_valid(hostname, std::bind(&torrent::address_info_lookup, hostname, AF_INET, 0));
+-}
+-
+-static bool
+-test_create_inet_throws(const char* hostname) {
+-  return test_create_throws(hostname, std::bind(&torrent::address_info_lookup, hostname, AF_INET, 0));
+-}
+-
+-static torrent::socket_address_key
+-test_create_inet6(const char* hostname) {
+-  return test_create_valid(hostname, std::bind(&torrent::address_info_lookup, hostname, AF_INET6, 0));
+-}
+-
+-static bool
+-test_create_inet6_throws(const char* hostname) {
+-  return test_create_throws(hostname, std::bind(&torrent::address_info_lookup, hostname, AF_INET6, 0));
+-}
+-
+-//
+-// Basic tests:
+-//
+-
+-void
+-test_socket_address_key::test_basic() {
+-  CPPUNIT_ASSERT(test_create_inet("1.1.1.1").is_valid());
+-  CPPUNIT_ASSERT(test_create_inet_throws("1.1.1.300"));
+-
+-  CPPUNIT_ASSERT(test_create_inet6("ff01::1").is_valid());
+-  CPPUNIT_ASSERT(test_create_inet6("2001:0db8:85a3:0000:0000:8a2e:0370:7334").is_valid());
+-  CPPUNIT_ASSERT(test_create_inet6("2001:db8:a::123").is_valid());
+-
+-  CPPUNIT_ASSERT(test_create_inet6_throws("2001:db8:a::22123"));
+-}
+-
+-
+-// Test lexical comparison:
+diff --git a/test/torrent/object_stream_test.cc b/test/torrent/object_stream_test.cc
+index c8a17049..5ad0c23e 100644
+--- a/test/torrent/object_stream_test.cc
++++ b/test/torrent/object_stream_test.cc
+@@ -1,10 +1,8 @@
+ #include "config.h"
+ 
+-#define __STDC_CONSTANT_MACROS
+-
+ #include <iostream>
+ #include <sstream>
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <torrent/object.h>
+ 
+ #include "object_stream_test.h"
+diff --git a/test/torrent/tracker_controller_features.cc b/test/torrent/tracker_controller_features.cc
+index 63f163f5..0a6a57d6 100644
+--- a/test/torrent/tracker_controller_features.cc
++++ b/test/torrent/tracker_controller_features.cc
+@@ -1,7 +1,7 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <iostream>
+-#include lt_tr1_functional
+ 
+ #include "rak/priority_queue_default.h"
+ 
+diff --git a/test/torrent/tracker_controller_requesting.cc b/test/torrent/tracker_controller_requesting.cc
+index 5bc25169..92e664b3 100644
+--- a/test/torrent/tracker_controller_requesting.cc
++++ b/test/torrent/tracker_controller_requesting.cc
+@@ -1,7 +1,7 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <iostream>
+-#include lt_tr1_functional
+ 
+ #include "rak/priority_queue_default.h"
+ 
+diff --git a/test/torrent/tracker_controller_test.cc b/test/torrent/tracker_controller_test.cc
+index 823a9d34..9406c99e 100644
+--- a/test/torrent/tracker_controller_test.cc
++++ b/test/torrent/tracker_controller_test.cc
+@@ -1,7 +1,7 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <iostream>
+-#include lt_tr1_functional
+ 
+ #include "rak/priority_queue_default.h"
+ 
+diff --git a/test/torrent/tracker_list_features_test.cc b/test/torrent/tracker_list_features_test.cc
+index 57c05f40..5257b1a7 100644
+--- a/test/torrent/tracker_list_features_test.cc
++++ b/test/torrent/tracker_list_features_test.cc
+@@ -1,6 +1,6 @@
+ #include "config.h"
+ 
+-#include lt_tr1_functional
++#include <functional>
+ 
+ #include "torrent/http.h"
+ #include "net/address_list.h"
+diff --git a/test/torrent/utils/directory_events_test.cc b/test/torrent/utils/directory_events_test.cc
+index 2cea5ab5..b97fd1d4 100644
+--- a/test/torrent/utils/directory_events_test.cc
++++ b/test/torrent/utils/directory_events_test.cc
+@@ -1,6 +1,6 @@
+ #include "config.h"
+ 
+-#include <tr1/functional>
++#include <functional>
+ #include <torrent/exceptions.h>
+ #include <torrent/utils/directory_events.h>
+ 
+@@ -8,8 +8,6 @@
+ 
+ CPPUNIT_TEST_SUITE_REGISTRATION(utils_directory_events_test);
+ 
+-namespace tr1 { using namespace std::tr1; }
+-
+ void
+ utils_directory_events_test::setUp() {
+ }
+diff --git a/test/torrent/utils/log_buffer_test.h b/test/torrent/utils/log_buffer_test.h
+deleted file mode 100644
+index f2824594..00000000
+--- a/test/torrent/utils/log_buffer_test.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "torrent/utils/log_buffer.h"
+-
+-class utils_log_buffer_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(utils_log_buffer_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST(test_timestamps);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp();
+-  void tearDown();
+-
+-  void test_basic();
+-  void test_timestamps();
+-};
+diff --git a/test/torrent/utils/log_test.cc b/test/torrent/utils/log_test.cc
+index 9f975636..8cc00ef8 100644
+--- a/test/torrent/utils/log_test.cc
++++ b/test/torrent/utils/log_test.cc
+@@ -3,8 +3,9 @@
+ #include <algorithm>
+ #include <cstring>
+ #include <fstream>
++#include <functional>
+ #include <iostream>
+-#include lt_tr1_functional
++
+ #include <torrent/exceptions.h>
+ #include <torrent/utils/log.h>
+ 
+@@ -37,6 +38,7 @@ void
+ utils_log_test::setUp() {
+   // Don't initialize since this creates the group->child connections.
+   //  torrent::log_initialize();
++  torrent::log_cleanup();
+ }
+ 
+ void
+diff --git a/test/torrent/utils/net_test.cc b/test/torrent/utils/net_test.cc
+deleted file mode 100644
+index d136e869..00000000
+--- a/test/torrent/utils/net_test.cc
++++ /dev/null
+@@ -1,32 +0,0 @@
+-#include "config.h"
+-
+-#include <torrent/exceptions.h>
+-#include <torrent/utils/net.h>
+-
+-#include "net_test.h"
+-
+-CPPUNIT_TEST_SUITE_REGISTRATION(utils_net_test);
+-
+-static void inc_value(int* value) { (*value)++; }
+-
+-#define LTUNIT_AI_CALL(lt_ai, lt_flags) {                               \
+-  int test_value = 0;                                                   \
+-  CPPUNIT_ASSERT(torrent::address_info_call(ai, 0, std::bind(&inc_value, &test_value))); \
+-  CPPUNIT_ASSERT(test_value); }                                         \
+-
+-void
+-utils_net_test::setUp() {
+-}
+-
+-void
+-utils_net_test::tearDown() {
+-}
+-
+-void
+-utils_net_test::test_basic() {
+-  addrinfo* ai = torrent::address_info_lookup("localhost", AF_INET, SOCK_STREAM);
+-
+-  LTUNIT_AI_CALL(ai, 0);
+-
+-  torrent::address_info_free(ai);
+-}
+diff --git a/test/torrent/utils/net_test.h b/test/torrent/utils/net_test.h
+deleted file mode 100644
+index e538ab39..00000000
+--- a/test/torrent/utils/net_test.h
++++ /dev/null
+@@ -1,15 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "torrent/utils/net.h"
+-
+-class utils_net_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(utils_net_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp();
+-  void tearDown();
+-
+-  void test_basic();
+-};
+diff --git a/test/torrent/utils/option_strings_test.cc b/test/torrent/utils/option_strings_test.cc
+index c6302f98..a9bdcc89 100644
+--- a/test/torrent/utils/option_strings_test.cc
++++ b/test/torrent/utils/option_strings_test.cc
+@@ -1,8 +1,9 @@
+ #include "config.h"
+ 
+ #include <fstream>
++#include <functional>
+ #include <iostream>
+-#include lt_tr1_functional
++
+ #include <torrent/exceptions.h>
+ #include <torrent/utils/option_strings.h>
+ 
+diff --git a/test/torrent/utils/test_extents.cc b/test/torrent/utils/test_extents.cc
+index d6b8d11d..87424d62 100644
+--- a/test/torrent/utils/test_extents.cc
++++ b/test/torrent/utils/test_extents.cc
+@@ -2,7 +2,7 @@
+ 
+ #include "test_extents.h"
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <iostream>
+ #include <torrent/utils/extents.h>
+ 
+diff --git a/test/torrent/utils/log_buffer_test.cc b/test/torrent/utils/test_log_buffer.cc
+similarity index 86%
+rename from test/torrent/utils/log_buffer_test.cc
+rename to test/torrent/utils/test_log_buffer.cc
+index a0ede0a0..a56a5365 100644
+--- a/test/torrent/utils/log_buffer_test.cc
++++ b/test/torrent/utils/test_log_buffer.cc
+@@ -1,23 +1,23 @@
+ #include "config.h"
+ 
+-#include <torrent/utils/log_buffer.h>
++#include "test_log_buffer.h"
+ 
+ #include "globals.h"
+-#include "log_buffer_test.h"
++#include <torrent/utils/log_buffer.h>
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(utils_log_buffer_test);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_log_buffer, "torrent/utils");
+ 
+ void
+-utils_log_buffer_test::setUp() {
++test_log_buffer::setUp() {
+   torrent::cachedTime = rak::timer::from_seconds(1000);
+ }
+ 
+ void
+-utils_log_buffer_test::tearDown() {
++test_log_buffer::tearDown() {
+ }
+ 
+ void
+-utils_log_buffer_test::test_basic() {
++test_log_buffer::test_basic() {
+   torrent::log_buffer log;
+ 
+   log.lock();
+@@ -44,7 +44,7 @@ utils_log_buffer_test::test_basic() {
+ }
+ 
+ void
+-utils_log_buffer_test::test_timestamps() {
++test_log_buffer::test_timestamps() {
+   torrent::log_buffer log;
+ 
+   log.lock_and_push_log("foobar", 6, 0);
+diff --git a/test/torrent/utils/test_log_buffer.h b/test/torrent/utils/test_log_buffer.h
+new file mode 100644
+index 00000000..290df4c1
+--- /dev/null
++++ b/test/torrent/utils/test_log_buffer.h
+@@ -0,0 +1,17 @@
++#include "helpers/test_fixture.h"
++
++class test_log_buffer : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_log_buffer);
++
++  CPPUNIT_TEST(test_basic);
++  CPPUNIT_TEST(test_timestamps);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void setUp();
++  void tearDown();
++
++  void test_basic();
++  void test_timestamps();
++};
+diff --git a/test/torrent/utils/test_uri_parser.cc b/test/torrent/utils/test_uri_parser.cc
+index c3b46eef..1f4bebe8 100644
+--- a/test/torrent/utils/test_uri_parser.cc
++++ b/test/torrent/utils/test_uri_parser.cc
+@@ -2,7 +2,7 @@
+ 
+ #include "test_uri_parser.h"
+ 
+-#include <inttypes.h>
++#include <cinttypes>
+ #include <iostream>
+ #include <torrent/utils/uri_parser.h>
+ 
+diff --git a/test/torrent/utils/thread_base_test.cc b/test/torrent/utils/thread_base_test.cc
+index 5cb7553f..8366c9ba 100644
+--- a/test/torrent/utils/thread_base_test.cc
++++ b/test/torrent/utils/thread_base_test.cc
+@@ -1,7 +1,8 @@
+ #include "config.h"
+ 
++#include <functional>
+ #include <unistd.h>
+-#include lt_tr1_functional
++
+ #include <torrent/exceptions.h>
+ #include <torrent/poll_select.h>
+ #include <torrent/utils/thread_base.h>
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0028-libtorrent.pc.in-add-Libs.Private-202.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0028-libtorrent.pc.in-add-Libs.Private-202.patch
new file mode 100644
index 000000000..d81548ceb
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0028-libtorrent.pc.in-add-Libs.Private-202.patch
@@ -0,0 +1,26 @@ 
+From b656a77864bd322d69522f1f9d922404066e5a7c Mon Sep 17 00:00:00 2001
+From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+Date: Mon, 21 Oct 2019 09:32:15 +0200
+Subject: [PATCH] libtorrent.pc.in: add Libs.Private (#202)
+
+Add Libs.Private: -lz so applications that want to link statically with
+libtorrent (such as rtorrent) will know that they must link with -lz
+
+Fixes:
+ - http://autobuild.buildroot.org/results/075598e1699c2ac20a4dfbcb5695bbb7343f9a86
+
+Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+---
+ libtorrent.pc.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libtorrent.pc.in b/libtorrent.pc.in
+index cf6612bc..6108f7e9 100644
+--- a/libtorrent.pc.in
++++ b/libtorrent.pc.in
+@@ -7,4 +7,5 @@ Name: libtorrent
+ Description: A BitTorrent library
+ Version: @VERSION@
+ Libs: -L${libdir} -ltorrent
++Libs.Private: -lz
+ Cflags: -I${includedir}
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0029-Fix-for-inotify-missing-quickly-renamed-files-203.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0029-Fix-for-inotify-missing-quickly-renamed-files-203.patch
new file mode 100644
index 000000000..59cf76cad
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0029-Fix-for-inotify-missing-quickly-renamed-files-203.patch
@@ -0,0 +1,27 @@ 
+From 7c80dc3e3a47dd996ca0554fce4f69d16761a9c9 Mon Sep 17 00:00:00 2001
+From: Tadej Obrstar <tadej.obrstar@gmail.com>
+Date: Sun, 1 Dec 2019 06:59:25 +0100
+Subject: [PATCH] Fix for inotify missing quickly renamed files (#203)
+
+---
+ src/torrent/utils/directory_events.cc | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/torrent/utils/directory_events.cc b/src/torrent/utils/directory_events.cc
+index 5d789f4e..8dcc2a61 100644
+--- a/src/torrent/utils/directory_events.cc
++++ b/src/torrent/utils/directory_events.cc
+@@ -154,8 +154,11 @@ directory_events::event_read() {
+     wd_list::const_iterator itr = std::find_if(m_wd_list.begin(), m_wd_list.end(),
+                                                std::bind(&watch_descriptor::compare_desc, std::placeholders::_1, event->wd));
+ 
+-    if (itr != m_wd_list.end())
+-      itr->slot(itr->path + event->name);
++    if (itr != m_wd_list.end()) {
++      std::string sname(event->name);
++      if((sname.substr(sname.find_last_of(".") ) == ".torrent"))
++        itr->slot(itr->path + event->name);
++    }
+ 
+     event = (struct inotify_event*)(next_event);
+   }
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0030-Fix-compiler-warnings.-204.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0030-Fix-compiler-warnings.-204.patch
new file mode 100644
index 000000000..5b26f959f
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0030-Fix-compiler-warnings.-204.patch
@@ -0,0 +1,470 @@ 
+From 81897862edea81e9620493c473f488d1820bcf93 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Tue, 3 Dec 2019 21:53:48 +0900
+Subject: [PATCH] Fix compiler warnings. (#204)
+
+---
+ configure.ac                      |  6 ++-
+ scripts/ax_execinfo.m4            | 67 +++++++++++++++++++++++++++++++
+ scripts/common.m4                 | 15 -------
+ scripts/rak_execinfo.m4           | 11 +++++
+ src/torrent/exceptions.cc         |  4 +-
+ test/Makefile.am                  | 15 ++-----
+ test/helpers/expect_fd.h          |  8 ++--
+ test/helpers/mock_compare.h       |  6 +--
+ test/helpers/progress_listener.cc |  3 +-
+ test/main.cc                      |  4 +-
+ test/net/Makefile.am              | 40 ++++++++++++++++++
+ test/torrent/net/Makefile.am      | 44 ++++++++++++++++++++
+ test/torrent/net/test_fd.cc       | 48 +++++++++++-----------
+ 13 files changed, 207 insertions(+), 64 deletions(-)
+ create mode 100644 scripts/ax_execinfo.m4
+ create mode 100644 scripts/rak_execinfo.m4
+ create mode 100644 test/net/Makefile.am
+ create mode 100644 test/torrent/net/Makefile.am
+
+diff --git a/configure.ac b/configure.ac
+index 620ca552..b6708366 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -33,6 +33,7 @@ RAK_CHECK_CXXFLAGS
+ RAK_ENABLE_DEBUG
+ RAK_ENABLE_EXTRA_DEBUG
+ RAK_ENABLE_WERROR
++RAK_DISABLE_BACKTRACE
+ 
+ RAK_CHECK_CXX11
+ 
+@@ -57,8 +58,8 @@ TORRENT_WITH_INOTIFY
+ 
+ CC_ATTRIBUTE_VISIBILITY
+ 
+-AX_PTHREAD
+ AX_CHECK_ZLIB
++AX_PTHREAD
+ 
+ PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
+ 
+@@ -74,7 +75,6 @@ AC_CHECK_FUNCS(posix_memalign)
+ TORRENT_CHECK_MADVISE()
+ TORRENT_CHECK_CACHELINE()
+ TORRENT_CHECK_POPCOUNT()
+-TORRENT_CHECK_EXECINFO()
+ TORRENT_CHECK_PTHREAD_SETNAME_NP()
+ TORRENT_MINCORE()
+ 
+@@ -111,4 +111,6 @@ AC_OUTPUT([
+ 	src/tracker/Makefile
+ 	src/utils/Makefile
+         test/Makefile
++        test/torrent/net/Makefile
++        test/net/Makefile
+ ])
+diff --git a/scripts/ax_execinfo.m4 b/scripts/ax_execinfo.m4
+new file mode 100644
+index 00000000..0ff5fc0e
+--- /dev/null
++++ b/scripts/ax_execinfo.m4
+@@ -0,0 +1,67 @@
++# ===========================================================================
++#       https://www.gnu.org/software/autoconf-archive/ax_execinfo.html
++# ===========================================================================
++#
++# SYNOPSIS
++#
++#   AX_EXECINFO([ACTION-IF-EXECINFO-H-IS-FOUND], [ACTION-IF-EXECINFO-H-IS-NOT-FOUND], [ADDITIONAL-TYPES-LIST])
++#
++# DESCRIPTION
++#
++#   Checks for execinfo.h header and if the len parameter/return type can be
++#   found from a list, also define backtrace_size_t to that type.
++#
++#   By default the list of types to try contains int and size_t, but should
++#   some yet undiscovered system use e.g. unsigned, the 3rd argument can be
++#   used for extensions. I'd like to hear of further suggestions.
++#
++#   Executes ACTION-IF-EXECINFO-H-IS-FOUND when present and the execinfo.h
++#   header is found or ACTION-IF-EXECINFO-H-IS-NOT-FOUND in case the header
++#   seems unavailable.
++#
++#   Also adds -lexecinfo to LIBS on BSD if needed.
++#
++# LICENSE
++#
++#   Copyright (c) 2014 Thomas Jahns <jahns@dkrz.de>
++#
++#   Copying and distribution of this file, with or without modification, are
++#   permitted in any medium without royalty provided the copyright notice
++#   and this notice are preserved. This file is offered as-is, without any
++#   warranty.
++
++#serial 2
++
++AC_DEFUN([AX_EXECINFO],
++  [AC_CHECK_HEADERS([execinfo.h])
++   AS_IF([test x"$ac_cv_header_execinfo_h" = xyes],
++     [AC_CACHE_CHECK([size parameter type for backtrace()],
++	[ax_cv_proto_backtrace_type],
++	[AC_LANG_PUSH([C])
++	 for ax_cv_proto_backtrace_type in size_t int m4_ifnblank([$3],[$3 ])none; do
++	   AS_IF([test "${ax_cv_proto_backtrace_type}" = none],
++	     [ax_cv_proto_backtrace_type= ; break])
++	   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
++#include <execinfo.h>
++extern
++${ax_cv_proto_backtrace_type} backtrace(void **addrlist, ${ax_cv_proto_backtrace_type} len);
++char **backtrace_symbols(void *const *buffer, ${ax_cv_proto_backtrace_type} size);
++])],
++	   [break])
++	 done
++	 AC_LANG_POP([C])])])
++   AS_IF([test x${ax_cv_proto_backtrace_type} != x],
++     [AC_DEFINE_UNQUOTED([backtrace_size_t], [$ax_cv_proto_backtrace_type],
++        [Defined to return type of backtrace().])])
++   AC_SEARCH_LIBS([backtrace],[execinfo])
++   AS_IF([test x"${ax_cv_proto_backtrace_type}" != x -a x"$ac_cv_header_execinfo_h" = xyes -a x"$ac_cv_search_backtrace" != xno],
++     [AC_DEFINE([HAVE_BACKTRACE],[1],
++        [Defined if backtrace() could be fully identified.])
++     ]m4_ifnblank([$1],[$1
++]),m4_ifnblank([$2],[$2
++]))])
++dnl
++dnl Local Variables:
++dnl mode: autoconf
++dnl End:
++dnl
+diff --git a/scripts/common.m4 b/scripts/common.m4
+index b6d051f5..55e8d66e 100644
+--- a/scripts/common.m4
++++ b/scripts/common.m4
+@@ -150,21 +150,6 @@ dnl   Need to fix this so that it uses the stuff defined by the system.
+   ])
+ ])
+ 
+-AC_DEFUN([TORRENT_CHECK_EXECINFO], [
+-  AC_MSG_CHECKING(for execinfo.h)
+-
+-  AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+-      #include <execinfo.h>
+-      int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
+-      ])],
+-    [
+-      AC_MSG_RESULT(yes)
+-      AC_DEFINE(USE_EXECINFO, 1, Use execinfo.h)
+-    ], [
+-      AC_MSG_RESULT(no)
+-  ])
+-])
+-
+ AC_DEFUN([TORRENT_CHECK_ALIGNED], [
+   AC_MSG_CHECKING(the byte alignment)
+ 
+diff --git a/scripts/rak_execinfo.m4 b/scripts/rak_execinfo.m4
+new file mode 100644
+index 00000000..c1d9b2f8
+--- /dev/null
++++ b/scripts/rak_execinfo.m4
+@@ -0,0 +1,11 @@
++AC_DEFUN([RAK_DISABLE_BACKTRACE], [
++  AC_ARG_ENABLE(backtrace,
++    AC_HELP_STRING([--disable-backtrace], [disable backtrace information [[default=no]]]),
++    [
++        if test "$enableval" = "yes"; then
++            AX_EXECINFO
++        fi
++    ],[
++        AX_EXECINFO
++    ])
++])
+diff --git a/src/torrent/exceptions.cc b/src/torrent/exceptions.cc
+index 2aeca1d7..f834f9fa 100644
+--- a/src/torrent/exceptions.cc
++++ b/src/torrent/exceptions.cc
+@@ -42,7 +42,7 @@
+ #include <sstream>
+ #include <unistd.h>
+ 
+-#ifdef USE_EXECINFO
++#ifdef HAVE_BACKTRACE
+ #include <execinfo.h>
+ #endif
+ 
+@@ -75,7 +75,7 @@ internal_error::initialize(const std::string& msg) {
+ 
+   std::stringstream output;
+ 
+-#ifdef USE_EXECINFO
++#ifdef HAVE_BACKTRACE
+   void* stackPtrs[20];
+ 
+   // Print the stack and exit.
+diff --git a/test/Makefile.am b/test/Makefile.am
+index b60a86a6..23b260e4 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -1,3 +1,5 @@
++SUBDIRS = torrent/net net
++
+ TESTS = LibTorrentTest
+ AUTOMAKE_OPTIONS = subdir-objects
+ 
+@@ -43,19 +45,9 @@ LibTorrentTest_SOURCES = \
+ 	data/hash_queue_test.cc \
+ 	data/hash_queue_test.h \
+ 	\
+-	net/test_socket_listen.cc \
+-	net/test_socket_listen.h \
+-	\
+ 	protocol/test_request_list.cc \
+ 	protocol/test_request_list.h \
+ 	\
+-	torrent/net/test_address_info.cc \
+-	torrent/net/test_address_info.h \
+-	torrent/net/test_fd.cc \
+-	torrent/net/test_fd.h \
+-	torrent/net/test_socket_address.cc \
+-	torrent/net/test_socket_address.h \
+-	\
+ 	torrent/utils/log_test.cc \
+ 	torrent/utils/log_test.h \
+ 	torrent/utils/option_strings_test.cc \
+@@ -97,9 +89,10 @@ LibTorrentTest_SOURCES = \
+ 	torrent/tracker_timeout_test.h \
+ 	tracker/tracker_http_test.cc \
+ 	tracker/tracker_http_test.h \
++	\
+ 	main.cc
+ 
+ LibTorrentTest_CXXFLAGS = $(CPPUNIT_CFLAGS)
+-LibTorrentTest_LDFLAGS = $(CPPUNIT_LIBS)  -ldl
++LibTorrentTest_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+ 
+ AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/src
+diff --git a/test/helpers/expect_fd.h b/test/helpers/expect_fd.h
+index 178cbabc..cc77c34a 100644
+--- a/test/helpers/expect_fd.h
++++ b/test/helpers/expect_fd.h
+@@ -18,15 +18,15 @@ sap_cache_copy_addr_c_ptr(sap_cache_type& sap_cache, const torrent::c_sa_unique_
+ 
+ inline void
+ expect_event_open_re(int idx) {
+-  mock_expect(&torrent::poll_event_open, mock_compare_map<torrent::Event>::begin_pointer + idx);
+-  mock_expect(&torrent::poll_event_insert_read, mock_compare_map<torrent::Event>::begin_pointer + idx);
+-  mock_expect(&torrent::poll_event_insert_error, mock_compare_map<torrent::Event>::begin_pointer + idx);
++  mock_expect(&torrent::poll_event_open, mock_compare_map<torrent::Event>::begin_pointer() + idx);
++  mock_expect(&torrent::poll_event_insert_read, mock_compare_map<torrent::Event>::begin_pointer() + idx);
++  mock_expect(&torrent::poll_event_insert_error, mock_compare_map<torrent::Event>::begin_pointer() + idx);
+ }
+ 
+ inline void
+ expect_event_closed_fd(int idx, int fd) {
+   mock_expect(&torrent::fd__close, 0, fd);
+-  mock_expect(&torrent::poll_event_closed, mock_compare_map<torrent::Event>::begin_pointer + idx);
++  mock_expect(&torrent::poll_event_closed, mock_compare_map<torrent::Event>::begin_pointer() + idx);
+ }
+ 
+ inline void
+diff --git a/test/helpers/mock_compare.h b/test/helpers/mock_compare.h
+index 3ea90305..3cc8d075 100644
+--- a/test/helpers/mock_compare.h
++++ b/test/helpers/mock_compare.h
+@@ -34,11 +34,11 @@ template <typename T>
+ struct mock_compare_map {
+   typedef std::map<const T*, const T*> values_type;
+ 
+-  constexpr static T* begin_pointer = reinterpret_cast<T*>(0x1000);
+-  constexpr static T* end_pointer = reinterpret_cast<T*>(0x2000);
++  static T* begin_pointer() { return reinterpret_cast<T*>(0x1000); }
++  static T* end_pointer() { return reinterpret_cast<T*>(0x2000); }
+ 
+   static bool is_key(const T* k) {
+-    return k >= begin_pointer && k < end_pointer;
++    return k >= begin_pointer() && k < end_pointer();
+   }
+ 
+   static bool has_key(const T* k) {
+diff --git a/test/helpers/progress_listener.cc b/test/helpers/progress_listener.cc
+index 02803ffc..c2b60bcd 100644
+--- a/test/helpers/progress_listener.cc
++++ b/test/helpers/progress_listener.cc
+@@ -54,7 +54,8 @@ void
+ progress_listener::startSuite(CppUnit::Test *suite) {
+   m_test_path.push_back(suite);
+ 
+-  std::cout << std::endl << get_test_path(m_test_path) << suite->getName() << ":" << std::endl;
++  if (suite->countTestCases() > 0)
++    std::cout << std::endl << get_test_path(m_test_path) << suite->getName() << ":" << std::endl;
+ }
+ 
+ void
+diff --git a/test/main.cc b/test/main.cc
+index da93fead..e8a00e1f 100644
+--- a/test/main.cc
++++ b/test/main.cc
+@@ -12,7 +12,7 @@
+ #include <cppunit/extensions/TestFactoryRegistry.h>
+ #include <cppunit/ui/text/TestRunner.h>
+ 
+-#ifdef USE_EXECINFO
++#ifdef HAVE_BACKTRACE
+ #include <execinfo.h>
+ #endif
+ 
+@@ -29,7 +29,7 @@ do_test_panic(int signum) {
+ 
+   std::cout << std::endl << std::endl << "Caught " << strsignal(signum) << ", dumping stack:" << std::endl << std::endl;
+   
+-#ifdef USE_EXECINFO
++#ifdef HAVE_BACKTRACE
+   void* stackPtrs[20];
+ 
+   // Print the stack and exit.
+diff --git a/test/net/Makefile.am b/test/net/Makefile.am
+new file mode 100644
+index 00000000..bb951814
+--- /dev/null
++++ b/test/net/Makefile.am
+@@ -0,0 +1,40 @@
++TESTS = LibTorrentTestNet
++AUTOMAKE_OPTIONS = subdir-objects
++
++check_PROGRAMS = $(TESTS)
++LibTorrentTestNet_LDADD = \
++	../../src/libtorrent.la \
++	../../src/torrent/libsub_torrent.la \
++	../../src/torrent/data/libsub_torrentdata.la \
++	../../src/torrent/download/libsub_torrentdownload.la \
++	../../src/torrent/peer/libsub_torrentpeer.la \
++	../../src/data/libsub_data.la \
++	../../src/dht/libsub_dht.la \
++	../../src/net/libsub_net.la \
++	../../src/protocol/libsub_protocol.la \
++	../../src/download/libsub_download.la \
++	../../src/tracker/libsub_tracker.la \
++	../../src/utils/libsub_utils.la \
++	../../src/torrent/utils/libsub_torrentutils.la
++
++LibTorrentTestNet_SOURCES = \
++	../helpers/expect_fd.h \
++	../helpers/expect_utils.h \
++	../helpers/mock_compare.h \
++	../helpers/mock_function.cc \
++	../helpers/mock_function.h \
++	../helpers/network.h \
++	../helpers/progress_listener.cc \
++	../helpers/progress_listener.h \
++	../helpers/test_fixture.cc \
++	../helpers/test_fixture.h \
++	\
++	test_socket_listen.cc \
++	test_socket_listen.h \
++	\
++	../main.cc
++
++LibTorrentTestNet_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrentTestNet_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++
++AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/test
+diff --git a/test/torrent/net/Makefile.am b/test/torrent/net/Makefile.am
+new file mode 100644
+index 00000000..8a531cc1
+--- /dev/null
++++ b/test/torrent/net/Makefile.am
+@@ -0,0 +1,44 @@
++TESTS = LibTorrentTestTorrentNet
++AUTOMAKE_OPTIONS = subdir-objects
++
++check_PROGRAMS = $(TESTS)
++LibTorrentTestTorrentNet_LDADD = \
++	../../../src/libtorrent.la \
++	../../../src/torrent/libsub_torrent.la \
++	../../../src/torrent/data/libsub_torrentdata.la \
++	../../../src/torrent/download/libsub_torrentdownload.la \
++	../../../src/torrent/peer/libsub_torrentpeer.la \
++	../../../src/data/libsub_data.la \
++	../../../src/dht/libsub_dht.la \
++	../../../src/net/libsub_net.la \
++	../../../src/protocol/libsub_protocol.la \
++	../../../src/download/libsub_download.la \
++	../../../src/tracker/libsub_tracker.la \
++	../../../src/utils/libsub_utils.la \
++	../../../src/torrent/utils/libsub_torrentutils.la
++
++LibTorrentTestTorrentNet_SOURCES = \
++	../../helpers/expect_fd.h \
++	../../helpers/expect_utils.h \
++	../../helpers/mock_compare.h \
++	../../helpers/mock_function.cc \
++	../../helpers/mock_function.h \
++	../../helpers/network.h \
++	../../helpers/progress_listener.cc \
++	../../helpers/progress_listener.h \
++	../../helpers/test_fixture.cc \
++	../../helpers/test_fixture.h \
++	\
++	test_address_info.cc \
++	test_address_info.h \
++	test_fd.cc \
++	test_fd.h \
++	test_socket_address.cc \
++	test_socket_address.h \
++	\
++	../../main.cc
++
++LibTorrentTestTorrentNet_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrentTestTorrentNet_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++
++AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/test
+diff --git a/test/torrent/net/test_fd.cc b/test/torrent/net/test_fd.cc
+index 3cab0c5e..5e56f0f3 100644
+--- a/test/torrent/net/test_fd.cc
++++ b/test/torrent/net/test_fd.cc
+@@ -1,24 +1,24 @@
+-#include "config.h"
+-
+-#include "test_fd.h"
+-
+-#include <torrent/net/fd.h>
+-
+-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_fd, "torrent/net");
+-
+-void
+-test_fd::test_valid_flags() {
+-  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream));
+-  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_nonblock));
+-  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_reuse_address));
+-  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only));
+-  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v6only));
+-
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_v4only | torrent::fd_flag_v6only));
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_v6only));
+-
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags()));
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(~torrent::fd_flag_all)));
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(torrent::fd_flag_stream | ~torrent::fd_flag_all)));
+-  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(0x3245132)));
+-}
++#include "config.h"
++
++#include "test_fd.h"
++
++#include <torrent/net/fd.h>
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_fd, "torrent/net");
++
++void
++test_fd::test_valid_flags() {
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_nonblock));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_reuse_address));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v6only));
++
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_v4only | torrent::fd_flag_v6only));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_v6only));
++
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags()));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(~torrent::fd_flag_all)));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(torrent::fd_flag_stream | ~torrent::fd_flag_all)));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(0x3245132)));
++}
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0031-Fix-log-format-so-GCC-can-check-it.-205.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0031-Fix-log-format-so-GCC-can-check-it.-205.patch
new file mode 100644
index 000000000..0ecc0cfe5
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0031-Fix-log-format-so-GCC-can-check-it.-205.patch
@@ -0,0 +1,33 @@ 
+From e813c344b1e4aa89288febb2f59109972083f1bb Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Thu, 5 Dec 2019 01:55:53 -0800
+Subject: [PATCH] Fix log format so GCC can check it. (#205)
+
+---
+ src/torrent/utils/log.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/torrent/utils/log.cc b/src/torrent/utils/log.cc
+index b855a2c6..24932996 100644
+--- a/src/torrent/utils/log.cc
++++ b/src/torrent/utils/log.cc
+@@ -16,6 +16,8 @@
+ #include <functional>
+ #include <memory>
+ 
++#define GROUPFMT (group >= LOG_NON_CASCADING) ? ("%" PRIi32 " ") : ("%" PRIi32 " %c ")
++
+ namespace torrent {
+ 
+ struct log_cache_entry {
+@@ -356,9 +358,7 @@ log_gz_file_write(std::shared_ptr<log_gz_output>& outfile, const char* data, siz
+ 
+   // Normal groups are nul-terminated strings.
+   if (group >= 0) {
+-    const char* fmt = (group >= LOG_NON_CASCADING) ? ("%" PRIi32 " ") : ("%" PRIi32 " %c ");
+-
+-    int buffer_length = snprintf(buffer, 64, fmt,
++    int buffer_length = snprintf(buffer, 64, GROUPFMT,
+                                  cachedTime.seconds(),
+                                  log_level_char[group % 6]);
+     
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0032-Consolidate-make-script-to-optimize-build.-206.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0032-Consolidate-make-script-to-optimize-build.-206.patch
new file mode 100644
index 000000000..fa5cb294c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0032-Consolidate-make-script-to-optimize-build.-206.patch
@@ -0,0 +1,843 @@ 
+From 7b85e112ac2f59a39afa344148a946553c776142 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Fri, 6 Dec 2019 00:35:21 +0900
+Subject: [PATCH] Consolidate make script to optimize build. (#206)
+
+---
+ configure.ac                     |  14 +--
+ src/Makefile.am                  | 147 ++++++++++++++++++++++++-----
+ src/data/Makefile.am             |  28 ------
+ src/dht/Makefile.am              |  18 ----
+ src/download/Makefile.am         |  19 ----
+ src/net/Makefile.am              |  30 ------
+ src/protocol/Makefile.am         |  28 ------
+ src/torrent/Makefile.am          | 154 ++++++++++++++++++++++++++++---
+ src/torrent/download/Makefile.am |  22 -----
+ src/torrent/net/Makefile.am      |  25 -----
+ src/torrent/peer/Makefile.am     |  28 ------
+ src/torrent/utils/Makefile.am    |  41 --------
+ src/tracker/Makefile.am          |  11 ---
+ src/utils/Makefile.am            |  14 ---
+ test/Makefile.am                 |  92 +++++++++++++-----
+ 15 files changed, 338 insertions(+), 333 deletions(-)
+ delete mode 100644 src/data/Makefile.am
+ delete mode 100644 src/dht/Makefile.am
+ delete mode 100644 src/download/Makefile.am
+ delete mode 100644 src/net/Makefile.am
+ delete mode 100644 src/protocol/Makefile.am
+ delete mode 100644 src/torrent/download/Makefile.am
+ delete mode 100644 src/torrent/net/Makefile.am
+ delete mode 100644 src/torrent/peer/Makefile.am
+ delete mode 100644 src/torrent/utils/Makefile.am
+ delete mode 100644 src/tracker/Makefile.am
+ delete mode 100644 src/utils/Makefile.am
+
+diff --git a/configure.ac b/configure.ac
+index b6708366..e83710cc 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -17,7 +17,7 @@ AC_SUBST(LIBTORRENT_CURRENT)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_INFO)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_NO)
+ 
+-AM_INIT_AUTOMAKE([serial-tests])
++AM_INIT_AUTOMAKE([serial-tests subdir-objects])
+ AC_CONFIG_HEADERS(config.h)
+ 
+ AC_PROG_CXX
+@@ -98,18 +98,6 @@ AC_OUTPUT([
+ 	Makefile
+ 	src/Makefile
+ 	src/torrent/Makefile
+-	src/torrent/data/Makefile
+-	src/torrent/download/Makefile
+-	src/torrent/net/Makefile
+-	src/torrent/peer/Makefile
+-	src/torrent/utils/Makefile
+-	src/data/Makefile
+-	src/dht/Makefile
+-	src/download/Makefile
+-	src/net/Makefile
+-	src/protocol/Makefile
+-	src/tracker/Makefile
+-	src/utils/Makefile
+         test/Makefile
+         test/torrent/net/Makefile
+         test/net/Makefile
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 99aaace0..e96bd74b 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,30 +1,12 @@
+-SUBDIRS = \
+-	torrent \
+-	data \
+-	dht \
+-	download \
+-	net \
+-	protocol \
+-	tracker \
+-	utils
++SUBDIRS = torrent
+ 
+ lib_LTLIBRARIES = libtorrent.la
++noinst_LTLIBRARIES = libtorrent_other.la
+ 
+ libtorrent_la_LDFLAGS = -version-info $(LIBTORRENT_INTERFACE_VERSION_INFO)
+ libtorrent_la_LIBADD = \
+-	torrent/libsub_torrent.la \
+-	torrent/data/libsub_torrentdata.la \
+-	torrent/download/libsub_torrentdownload.la \
+-	torrent/net/libsub_torrentnet.la \
+-	torrent/peer/libsub_torrentpeer.la \
+-	torrent/utils/libsub_torrentutils.la \
+-	data/libsub_data.la \
+-	dht/libsub_dht.la \
+-	download/libsub_download.la \
+-	net/libsub_net.la \
+-	protocol/libsub_protocol.la \
+-	tracker/libsub_tracker.la \
+-	utils/libsub_utils.la
++	torrent/libtorrent_torrent.la \
++	libtorrent_other.la
+ 
+ libtorrent_la_SOURCES = \
+ 	globals.cc \
+@@ -36,4 +18,125 @@ libtorrent_la_SOURCES = \
+ 	thread_main.cc \
+ 	thread_main.h
+ 
++libtorrent_other_la_SOURCES = \
++	data/chunk.cc \
++	data/chunk.h \
++	data/chunk_handle.h \
++	data/chunk_iterator.h \
++	data/chunk_list.cc \
++	data/chunk_list.h \
++	data/chunk_list_node.h \
++	data/chunk_part.cc \
++	data/chunk_part.h \
++	data/hash_check_queue.cc \
++	data/hash_check_queue.h \
++	data/hash_chunk.cc \
++	data/hash_chunk.h \
++	data/hash_queue.cc \
++	data/hash_queue.h \
++	data/hash_queue_node.cc \
++	data/hash_queue_node.h \
++	data/hash_torrent.cc \
++	data/hash_torrent.h \
++	data/memory_chunk.cc \
++	data/memory_chunk.h \
++	data/socket_file.cc \
++	data/socket_file.h \
++	\
++	dht/dht_bucket.cc \
++	dht/dht_bucket.h \
++	dht/dht_hash_map.h \
++	dht/dht_node.cc \
++	dht/dht_node.h \
++	dht/dht_router.cc \
++	dht/dht_router.h \
++	dht/dht_server.cc \
++	dht/dht_server.h \
++	dht/dht_tracker.cc \
++	dht/dht_tracker.h \
++	dht/dht_transaction.cc \
++	dht/dht_transaction.h \
++	\
++	download/available_list.cc \
++	download/available_list.h \
++	download/chunk_selector.cc \
++	download/chunk_selector.h \
++	download/chunk_statistics.cc \
++	download/chunk_statistics.h \
++	download/delegator.cc \
++	download/delegator.h \
++	download/download_constructor.cc \
++	download/download_constructor.h \
++	download/download_main.cc \
++	download/download_main.h \
++	download/download_wrapper.cc \
++	download/download_wrapper.h \
++	\
++	net/address_list.cc \
++	net/address_list.h \
++	net/data_buffer.h \
++	net/local_addr.cc \
++	net/local_addr.h \
++	net/listen.cc \
++	net/listen.h \
++	net/protocol_buffer.h \
++	net/socket_base.cc \
++	net/socket_base.h \
++	net/socket_datagram.cc \
++	net/socket_datagram.h \
++	net/socket_fd.cc \
++	net/socket_fd.h \
++	net/socket_listen.cc \
++	net/socket_listen.h \
++	net/socket_set.cc \
++	net/socket_set.h \
++	net/socket_stream.cc \
++	net/socket_stream.h \
++	net/throttle_internal.cc \
++	net/throttle_internal.h \
++	net/throttle_list.cc \
++	net/throttle_list.h \
++	net/throttle_node.h \
++	\
++	protocol/encryption_info.h \
++	protocol/extensions.cc \
++	protocol/extensions.h \
++	protocol/handshake.cc \
++	protocol/handshake.h \
++	protocol/handshake_encryption.cc \
++	protocol/handshake_encryption.h \
++	protocol/handshake_manager.cc \
++	protocol/handshake_manager.h \
++	protocol/initial_seed.cc \
++	protocol/initial_seed.h \
++	protocol/peer_chunks.h \
++	protocol/peer_connection_base.cc \
++	protocol/peer_connection_base.h \
++	protocol/peer_connection_leech.cc \
++	protocol/peer_connection_leech.h \
++	protocol/peer_connection_metadata.cc \
++	protocol/peer_connection_metadata.h \
++	protocol/peer_factory.cc \
++	protocol/peer_factory.h \
++	protocol/protocol_base.h \
++	protocol/request_list.cc \
++	protocol/request_list.h \
++	\
++	tracker/tracker_dht.cc \
++	tracker/tracker_dht.h \
++	tracker/tracker_http.cc \
++	tracker/tracker_http.h \
++	tracker/tracker_udp.cc \
++	tracker/tracker_udp.h \
++	\
++	utils/diffie_hellman.cc \
++	utils/diffie_hellman.h \
++	utils/instrumentation.cc \
++	utils/instrumentation.h \
++	utils/rc4.h \
++	utils/sha1.h \
++	utils/sha_fast.cc \
++	utils/sha_fast.h \
++	utils/queue_buckets.h
++
+ AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
+diff --git a/src/data/Makefile.am b/src/data/Makefile.am
+deleted file mode 100644
+index ef41c9bd..00000000
+--- a/src/data/Makefile.am
++++ /dev/null
+@@ -1,28 +0,0 @@
+-noinst_LTLIBRARIES = libsub_data.la
+-
+-libsub_data_la_SOURCES = \
+-	chunk.cc \
+-	chunk.h \
+-	chunk_handle.h \
+-	chunk_iterator.h \
+-	chunk_list.cc \
+-	chunk_list.h \
+-	chunk_list_node.h \
+-	chunk_part.cc \
+-	chunk_part.h \
+-	hash_check_queue.cc \
+-	hash_check_queue.h \
+-	hash_chunk.cc \
+-	hash_chunk.h \
+-	hash_queue.cc \
+-	hash_queue.h \
+-	hash_queue_node.cc \
+-	hash_queue_node.h \
+-	hash_torrent.cc \
+-	hash_torrent.h \
+-	memory_chunk.cc \
+-	memory_chunk.h \
+-	socket_file.cc \
+-	socket_file.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
+deleted file mode 100644
+index a87c57bc..00000000
+--- a/src/dht/Makefile.am
++++ /dev/null
+@@ -1,18 +0,0 @@
+-noinst_LTLIBRARIES = libsub_dht.la
+-
+-libsub_dht_la_SOURCES = \
+-	dht_bucket.cc \
+-	dht_bucket.h \
+-	dht_hash_map.h \
+-	dht_node.cc \
+-	dht_node.h \
+-	dht_router.cc \
+-	dht_router.h \
+-	dht_server.cc \
+-	dht_server.h \
+-	dht_tracker.cc \
+-	dht_tracker.h \
+-	dht_transaction.cc \
+-	dht_transaction.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/download/Makefile.am b/src/download/Makefile.am
+deleted file mode 100644
+index 65ceaf97..00000000
+--- a/src/download/Makefile.am
++++ /dev/null
+@@ -1,19 +0,0 @@
+-noinst_LTLIBRARIES = libsub_download.la
+-
+-libsub_download_la_SOURCES = \
+-	available_list.cc \
+-	available_list.h \
+-	chunk_selector.cc \
+-	chunk_selector.h \
+-	chunk_statistics.cc \
+-	chunk_statistics.h \
+-	delegator.cc \
+-	delegator.h \
+-	download_constructor.cc \
+-	download_constructor.h \
+-	download_main.cc \
+-	download_main.h \
+-	download_wrapper.cc \
+-	download_wrapper.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/net/Makefile.am b/src/net/Makefile.am
+deleted file mode 100644
+index e3a8c7e1..00000000
+--- a/src/net/Makefile.am
++++ /dev/null
+@@ -1,30 +0,0 @@
+-noinst_LTLIBRARIES = libsub_net.la
+-
+-libsub_net_la_SOURCES = \
+-	address_list.cc \
+-	address_list.h \
+-	data_buffer.h \
+-	local_addr.cc \
+-	local_addr.h \
+-	listen.cc \
+-	listen.h \
+-	protocol_buffer.h \
+-	socket_base.cc \
+-        socket_base.h \
+-	socket_datagram.cc \
+-	socket_datagram.h \
+-	socket_fd.cc \
+-	socket_fd.h \
+-	socket_listen.cc \
+-	socket_listen.h \
+-	socket_set.cc \
+-	socket_set.h \
+-	socket_stream.cc \
+-	socket_stream.h \
+-	throttle_internal.cc \
+-	throttle_internal.h \
+-	throttle_list.cc \
+-	throttle_list.h \
+-	throttle_node.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/protocol/Makefile.am b/src/protocol/Makefile.am
+deleted file mode 100644
+index 2e9aba7a..00000000
+--- a/src/protocol/Makefile.am
++++ /dev/null
+@@ -1,28 +0,0 @@
+-noinst_LTLIBRARIES = libsub_protocol.la
+-
+-libsub_protocol_la_SOURCES = \
+-        encryption_info.h \
+-        extensions.cc \
+-        extensions.h \
+-        handshake.cc \
+-        handshake.h \
+-	handshake_encryption.cc \
+-	handshake_encryption.h \
+-        handshake_manager.cc \
+-        handshake_manager.h \
+-	initial_seed.cc \
+-	initial_seed.h \
+-	peer_chunks.h \
+-	peer_connection_base.cc \
+-	peer_connection_base.h \
+-	peer_connection_leech.cc \
+-	peer_connection_leech.h \
+-	peer_connection_metadata.cc \
+-	peer_connection_metadata.h \
+-	peer_factory.cc \
+-	peer_factory.h \
+-	protocol_base.h \
+-	request_list.cc \
+-	request_list.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/torrent/Makefile.am b/src/torrent/Makefile.am
+index 8cd26ce7..30157b95 100644
+--- a/src/torrent/Makefile.am
++++ b/src/torrent/Makefile.am
+@@ -1,13 +1,89 @@
+-SUBDIRS = \
+-	data \
+-	download \
+-	net \
+-	peer \
+-	utils
++noinst_LTLIBRARIES = libtorrent_torrent.la
+ 
+-noinst_LTLIBRARIES = libsub_torrent.la
+-
+-libsub_torrent_la_SOURCES = \
++libtorrent_torrent_la_SOURCES = \
++	data/block.cc \
++	data/block.h \
++	data/block_failed.h \
++	data/block_list.cc \
++	data/block_list.h \
++	data/block_transfer.h \
++	data/chunk_utils.cc \
++	data/chunk_utils.h \
++	data/download_data.cc \
++	data/download_data.h \
++	data/file.cc \
++	data/file.h \
++	data/file_list.cc \
++	data/file_list.h \
++	data/file_list_iterator.cc \
++	data/file_list_iterator.h \
++	data/file_manager.cc \
++	data/file_manager.h \
++	data/file_utils.cc \
++	data/file_utils.h \
++	data/piece.h \
++	data/transfer_list.cc \
++	data/transfer_list.h \
++\
++	download/choke_group.cc \
++	download/choke_group.h \
++	download/choke_queue.cc \
++	download/choke_queue.h \
++	download/download_manager.cc \
++	download/download_manager.h \
++	download/group_entry.h \
++	download/resource_manager.cc \
++	download/resource_manager.h \
++\
++	net/address_info.cc \
++	net/address_info.h \
++	net/fd.cc \
++	net/fd.h \
++	net/socket_address.cc \
++	net/socket_address.h \
++	net/socket_address_key.cc \
++	net/socket_address_key.h \
++	net/socket_event.cc \
++	net/socket_event.h \
++	net/types.h \
++\
++	peer/choke_status.h \
++	peer/client_info.cc \
++	peer/client_info.h \
++	peer/client_list.cc \
++	peer/client_list.h \
++	peer/connection_list.cc \
++	peer/connection_list.h \
++	peer/peer.cc \
++	peer/peer.h \
++        peer/peer_info.cc \
++        peer/peer_info.h \
++	peer/peer_list.cc \
++	peer/peer_list.h \
++\
++	utils/directory_events.cc \
++	utils/directory_events.h \
++	utils/extents.h \
++	utils/log.cc \
++	utils/log.h \
++	utils/log_buffer.cc \
++	utils/log_buffer.h \
++	utils/option_strings.cc \
++	utils/option_strings.h \
++	utils/random.cc \
++	utils/random.h \
++	utils/ranges.h \
++	utils/resume.cc \
++	utils/resume.h \
++	utils/signal_bitfield.cc \
++	utils/signal_bitfield.h \
++	utils/thread_base.cc \
++	utils/thread_base.h \
++	utils/thread_interrupt.cc \
++	utils/thread_interrupt.h \
++	utils/uri_parser.cc \
++	utils/uri_parser.h \
++\
+ 	bitfield.cc \
+ 	bitfield.h \
+ 	chunk_manager.cc \
+@@ -61,8 +137,64 @@ libsub_torrent_la_SOURCES = \
+ 
+ AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+ 
+-libtorrentincludedir = $(includedir)/torrent
+-libtorrentinclude_HEADERS = \
++libtorrent_torrent_data_includedir = $(includedir)/torrent/data
++libtorrent_torrent_data_include_HEADERS = \
++	data/block.h \
++	data/block_list.h \
++	data/block_transfer.h \
++	data/chunk_utils.h \
++	data/download_data.h \
++	data/file.h \
++	data/file_list.h \
++	data/file_list_iterator.h \
++	data/file_manager.h \
++	data/file_utils.h \
++	data/piece.h \
++	data/transfer_list.h
++
++libtorrent_torrent_download_includedir = $(includedir)/torrent/download
++libtorrent_torrent_download_include_HEADERS = \
++	download/choke_group.h \
++	download/choke_queue.h \
++	download/download_manager.h \
++	download/group_entry.h \
++	download/resource_manager.h
++
++libtorrent_torrent_net_includedir = $(includedir)/torrent/net
++libtorrent_torrent_net_include_HEADERS = \
++	net/address_info.h \
++	net/fd.h \
++	net/socket_address.h \
++	net/socket_address_key.h \
++	net/socket_event.h \
++	net/types.h
++
++libtorrent_torrent_peer_includedir = $(includedir)/torrent/peer
++libtorrent_torrent_peer_include_HEADERS = \
++	peer/choke_status.h \
++	peer/client_info.h \
++	peer/client_list.h \
++	peer/connection_list.h \
++	peer/peer.h \
++        peer/peer_info.h \
++	peer/peer_list.h
++
++libtorrent_torrent_utils_includedir = $(includedir)/torrent/utils
++libtorrent_torrent_utils_include_HEADERS = \
++	utils/directory_events.h \
++	utils/extents.h \
++	utils/log.h \
++	utils/log_buffer.h \
++	utils/option_strings.h \
++	utils/ranges.h \
++	utils/resume.h \
++	utils/signal_bitfield.h \
++	utils/thread_base.h \
++	utils/thread_interrupt.h \
++	utils/uri_parser.h
++
++libtorrent_torrent_includedir = $(includedir)/torrent
++libtorrent_torrent_include_HEADERS = \
+ 	bitfield.h \
+ 	chunk_manager.h \
+ 	common.h \
+diff --git a/src/torrent/download/Makefile.am b/src/torrent/download/Makefile.am
+deleted file mode 100644
+index f92c7aa4..00000000
+--- a/src/torrent/download/Makefile.am
++++ /dev/null
+@@ -1,22 +0,0 @@
+-noinst_LTLIBRARIES = libsub_torrentdownload.la
+-
+-libsub_torrentdownload_la_SOURCES = \
+-	choke_group.cc \
+-	choke_group.h \
+-	choke_queue.cc \
+-	choke_queue.h \
+-	download_manager.cc \
+-	download_manager.h \
+-	group_entry.h \
+-	resource_manager.cc \
+-	resource_manager.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir)
+-
+-libtorrentincludedir = $(includedir)/torrent/download
+-libtorrentinclude_HEADERS = \
+-	choke_group.h \
+-	choke_queue.h \
+-	download_manager.h \
+-	group_entry.h \
+-	resource_manager.h
+diff --git a/src/torrent/net/Makefile.am b/src/torrent/net/Makefile.am
+deleted file mode 100644
+index 35dd4774..00000000
+--- a/src/torrent/net/Makefile.am
++++ /dev/null
+@@ -1,25 +0,0 @@
+-noinst_LTLIBRARIES = libsub_torrentnet.la
+-
+-libsub_torrentnet_la_SOURCES = \
+-	address_info.cc \
+-	address_info.h \
+-	fd.cc \
+-	fd.h \
+-	socket_address.cc \
+-	socket_address.h \
+-	socket_address_key.cc \
+-	socket_address_key.h \
+-	socket_event.cc \
+-	socket_event.h \
+-	types.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir)
+-
+-libtorrentincludedir = $(includedir)/torrent/net
+-libtorrentinclude_HEADERS = \
+-	address_info.h \
+-	fd.h \
+-	socket_address.h \
+-	socket_address_key.h \
+-	socket_event.h \
+-	types.h
+diff --git a/src/torrent/peer/Makefile.am b/src/torrent/peer/Makefile.am
+deleted file mode 100644
+index 1324e88a..00000000
+--- a/src/torrent/peer/Makefile.am
++++ /dev/null
+@@ -1,28 +0,0 @@
+-noinst_LTLIBRARIES = libsub_torrentpeer.la
+-
+-libsub_torrentpeer_la_SOURCES = \
+-	choke_status.h \
+-	client_info.cc \
+-	client_info.h \
+-	client_list.cc \
+-	client_list.h \
+-	connection_list.cc \
+-	connection_list.h \
+-	peer.cc \
+-	peer.h \
+-        peer_info.cc \
+-        peer_info.h \
+-	peer_list.cc \
+-	peer_list.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir)
+-
+-libtorrentincludedir = $(includedir)/torrent/peer
+-libtorrentinclude_HEADERS = \
+-	choke_status.h \
+-	client_info.h \
+-	client_list.h \
+-	connection_list.h \
+-	peer.h \
+-        peer_info.h \
+-	peer_list.h
+diff --git a/src/torrent/utils/Makefile.am b/src/torrent/utils/Makefile.am
+deleted file mode 100644
+index a48786c6..00000000
+--- a/src/torrent/utils/Makefile.am
++++ /dev/null
+@@ -1,41 +0,0 @@
+-noinst_LTLIBRARIES = libsub_torrentutils.la
+-
+-libsub_torrentutils_la_SOURCES = \
+-	directory_events.cc \
+-	directory_events.h \
+-	extents.h \
+-	log.cc \
+-	log.h \
+-	log_buffer.cc \
+-	log_buffer.h \
+-	option_strings.cc \
+-	option_strings.h \
+-	random.cc \
+-	random.h \
+-	ranges.h \
+-	resume.cc \
+-	resume.h \
+-	signal_bitfield.cc \
+-	signal_bitfield.h \
+-	thread_base.cc \
+-	thread_base.h \
+-	thread_interrupt.cc \
+-	thread_interrupt.h \
+-	uri_parser.cc \
+-	uri_parser.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir)
+-
+-libtorrentincludedir = $(includedir)/torrent/utils
+-libtorrentinclude_HEADERS = \
+-	directory_events.h \
+-	extents.h \
+-	log.h \
+-	log_buffer.h \
+-	option_strings.h \
+-	ranges.h \
+-	resume.h \
+-	signal_bitfield.h \
+-	thread_base.h \
+-	thread_interrupt.h \
+-	uri_parser.h
+diff --git a/src/tracker/Makefile.am b/src/tracker/Makefile.am
+deleted file mode 100644
+index 2f1ae5cf..00000000
+--- a/src/tracker/Makefile.am
++++ /dev/null
+@@ -1,11 +0,0 @@
+-noinst_LTLIBRARIES = libsub_tracker.la
+-
+-libsub_tracker_la_SOURCES = \
+-	tracker_dht.cc \
+-	tracker_dht.h \
+-	tracker_http.cc \
+-	tracker_http.h \
+-	tracker_udp.cc \
+-	tracker_udp.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
+deleted file mode 100644
+index 27ce359b..00000000
+--- a/src/utils/Makefile.am
++++ /dev/null
+@@ -1,14 +0,0 @@
+-noinst_LTLIBRARIES = libsub_utils.la
+-
+-libsub_utils_la_SOURCES = \
+-	diffie_hellman.cc \
+-	diffie_hellman.h \
+-	instrumentation.cc \
+-	instrumentation.h \
+-	rc4.h \
+-	sha1.h \
+-	sha_fast.cc \
+-	sha_fast.h \
+-	queue_buckets.h
+-
+-AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+diff --git a/test/Makefile.am b/test/Makefile.am
+index 23b260e4..8b0291bb 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -1,25 +1,68 @@
+-SUBDIRS = torrent/net net
+-
+-TESTS = LibTorrentTest
+-AUTOMAKE_OPTIONS = subdir-objects
++TESTS = \
++	LibTorrent_Test_Torrent_Net \
++	LibTorrent_Test_Net \
++	LibTorrent_Test
+ 
+ check_PROGRAMS = $(TESTS)
+-LibTorrentTest_LDADD = \
++
++LibTorrent_Test_LDADD = \
+ 	../src/libtorrent.la \
+-	../src/torrent/libsub_torrent.la \
+-	../src/torrent/data/libsub_torrentdata.la \
+-	../src/torrent/download/libsub_torrentdownload.la \
+-	../src/torrent/peer/libsub_torrentpeer.la \
+-	../src/data/libsub_data.la \
+-	../src/dht/libsub_dht.la \
+-	../src/net/libsub_net.la \
+-	../src/protocol/libsub_protocol.la \
+-	../src/download/libsub_download.la \
+-	../src/tracker/libsub_tracker.la \
+-	../src/utils/libsub_utils.la \
+-	../src/torrent/utils/libsub_torrentutils.la
++	../src/libtorrent_other.la \
++	../src/torrent/libtorrent_torrent.la
++
++LibTorrent_Test_Net_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Torrent_Net_LDADD = $(LibTorrent_Test_LDADD)
++
++# LibTorrent_Test_SOURCES = \
++# 	helpers/expect_fd.h \
++# 	helpers/expect_utils.h \
++# 	helpers/mock_compare.h \
++# 	helpers/mock_function.cc \
++# 	helpers/mock_function.h \
++# 	helpers/network.h \
++# 	helpers/progress_listener.cc \
++# 	helpers/progress_listener.h \
++# 	helpers/test_fixture.cc \
++# 	helpers/test_fixture.h
++
++LibTorrent_Test_Torrent_Net_SOURCES = \
++	main.cc \
++	helpers/expect_fd.h \
++	helpers/expect_utils.h \
++	helpers/mock_compare.h \
++	helpers/mock_function.cc \
++	helpers/mock_function.h \
++	helpers/network.h \
++	helpers/progress_listener.cc \
++	helpers/progress_listener.h \
++	helpers/test_fixture.cc \
++	helpers/test_fixture.h \
++	\
++	torrent/net/test_address_info.cc \
++	torrent/net/test_address_info.h \
++	torrent/net/test_fd.cc \
++	torrent/net/test_fd.h \
++	torrent/net/test_socket_address.cc \
++	torrent/net/test_socket_address.h
+ 
+-LibTorrentTest_SOURCES = \
++LibTorrent_Test_Net_SOURCES = \
++	main.cc \
++	helpers/expect_fd.h \
++	helpers/expect_utils.h \
++	helpers/mock_compare.h \
++	helpers/mock_function.cc \
++	helpers/mock_function.h \
++	helpers/network.h \
++	helpers/progress_listener.cc \
++	helpers/progress_listener.h \
++	helpers/test_fixture.cc \
++	helpers/test_fixture.h \
++	\
++	net/test_socket_listen.cc \
++	net/test_socket_listen.h
++
++LibTorrent_Test_SOURCES = \
++	main.cc \
+ 	helpers/expect_fd.h \
+ 	helpers/expect_utils.h \
+ 	helpers/mock_compare.h \
+@@ -87,12 +130,15 @@ LibTorrentTest_SOURCES = \
+ 	torrent/tracker_list_features_test.h \
+ 	torrent/tracker_timeout_test.cc \
+ 	torrent/tracker_timeout_test.h \
+-	tracker/tracker_http_test.cc \
+-	tracker/tracker_http_test.h \
+ 	\
+-	main.cc
++	tracker/tracker_http_test.cc \
++	tracker/tracker_http_test.h
+ 
+-LibTorrentTest_CXXFLAGS = $(CPPUNIT_CFLAGS)
+-LibTorrentTest_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Torrent_Net_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Torrent_Net_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Net_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Net_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+ 
+ AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0033-Refactor-make-process.-207.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0033-Refactor-make-process.-207.patch
new file mode 100644
index 000000000..4c7a2038f
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0033-Refactor-make-process.-207.patch
@@ -0,0 +1,2710 @@ 
+From 9cdb950c0db2bad1a4d85b48f06419e2920aa114 Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Fri, 20 Dec 2019 00:37:38 +0900
+Subject: [PATCH] Refactor make process. (#207)
+
+---
+ configure.ac                                  |   3 +-
+ src/Makefile.am                               |   3 +-
+ src/manager.h                                 |  36 ---
+ src/thread_disk.h                             |  51 +---
+ src/torrent/utils/thread_base.cc              |  36 ---
+ src/torrent/utils/thread_base.h               |  48 +---
+ test/Makefile.am                              | 140 +++++------
+ ...{chunk_list_test.cc => test_chunk_list.cc} |  16 +-
+ .../{chunk_list_test.h => test_chunk_list.h}  |  13 +-
+ ...queue_test.cc => test_hash_check_queue.cc} |  33 ++-
+ ...k_queue_test.h => test_hash_check_queue.h} |  22 +-
+ ...{hash_queue_test.cc => test_hash_queue.cc} |  66 +++---
+ .../{hash_queue_test.h => test_hash_queue.h}  |  11 +-
+ test/helpers/progress_listener.cc             |   4 +-
+ test/helpers/test_fixture.h                   |  28 +--
+ test/helpers/test_thread.cc                   |  71 ++++++
+ test/helpers/test_thread.h                    |  59 +++++
+ test/helpers/test_utils.h                     |  16 ++
+ test/helpers/utils.h                          | 120 +++++-----
+ test/main.cc                                  |   4 +-
+ test/torrent/{http_test.cc => test_http.cc}   |  17 +-
+ test/torrent/{http_test.h => test_http.h}     |  11 +-
+ test/torrent/utils/option_strings_test.h      |  17 --
+ test/torrent/utils/signal_bitfield_test.h     |  23 --
+ test/torrent/utils/test_extents.cc            |  63 ++---
+ test/torrent/utils/test_extents.h             |   9 +-
+ .../utils/{log_test.cc => test_log.cc}        |  26 +-
+ test/torrent/utils/{log_test.h => test_log.h} |   8 +-
+ test/torrent/utils/test_log_buffer.cc         |  11 +-
+ test/torrent/utils/test_log_buffer.h          |   5 -
+ ...strings_test.cc => test_option_strings.cc} |  29 +--
+ test/torrent/utils/test_option_strings.h      |  10 +
+ test/torrent/utils/test_queue_buckets.cc      |  12 +-
+ test/torrent/utils/test_queue_buckets.h       |  11 +-
+ ...tfield_test.cc => test_signal_bitfield.cc} |  31 ++-
+ test/torrent/utils/test_signal_bitfield.h     |  22 ++
+ test/torrent/utils/test_thread_base.cc        | 169 +++++++++++++
+ test/torrent/utils/test_thread_base.h         |  25 ++
+ test/torrent/utils/test_uri_parser.cc         |  31 +--
+ test/torrent/utils/test_uri_parser.h          |  11 +-
+ test/torrent/utils/thread_base_test.cc        | 224 ------------------
+ test/torrent/utils/thread_base_test.h         |  86 -------
+ test/tracker/test_tracker_http.cc             |  11 +
+ test/tracker/test_tracker_http.h              |  12 +
+ test/tracker/tracker_http_test.cc             |  17 --
+ test/tracker/tracker_http_test.h              |  18 --
+ 46 files changed, 735 insertions(+), 954 deletions(-)
+ rename test/data/{chunk_list_test.cc => test_chunk_list.cc} (93%)
+ rename test/data/{chunk_list_test.h => test_chunk_list.h} (88%)
+ rename test/data/{hash_check_queue_test.cc => test_hash_check_queue.cc} (92%)
+ rename test/data/{hash_check_queue_test.h => test_hash_check_queue.h} (63%)
+ rename test/data/{hash_queue_test.cc => test_hash_queue.cc} (82%)
+ rename test/data/{hash_queue_test.h => test_hash_queue.h} (58%)
+ create mode 100755 test/helpers/test_thread.cc
+ create mode 100755 test/helpers/test_thread.h
+ create mode 100644 test/helpers/test_utils.h
+ rename test/torrent/{http_test.cc => test_http.cc} (94%)
+ rename test/torrent/{http_test.h => test_http.h} (63%)
+ delete mode 100644 test/torrent/utils/option_strings_test.h
+ delete mode 100644 test/torrent/utils/signal_bitfield_test.h
+ rename test/torrent/utils/{log_test.cc => test_log.cc} (92%)
+ rename test/torrent/utils/{log_test.h => test_log.h} (71%)
+ rename test/torrent/utils/{option_strings_test.cc => test_option_strings.cc} (65%)
+ create mode 100644 test/torrent/utils/test_option_strings.h
+ rename test/torrent/utils/{signal_bitfield_test.cc => test_signal_bitfield.cc} (85%)
+ create mode 100644 test/torrent/utils/test_signal_bitfield.h
+ create mode 100644 test/torrent/utils/test_thread_base.cc
+ create mode 100644 test/torrent/utils/test_thread_base.h
+ delete mode 100644 test/torrent/utils/thread_base_test.cc
+ delete mode 100644 test/torrent/utils/thread_base_test.h
+ create mode 100644 test/tracker/test_tracker_http.cc
+ create mode 100644 test/tracker/test_tracker_http.h
+ delete mode 100644 test/tracker/tracker_http_test.cc
+ delete mode 100644 test/tracker/tracker_http_test.h
+
+diff --git a/configure.ac b/configure.ac
+index e83710cc..88a46edd 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -21,6 +21,7 @@ AM_INIT_AUTOMAKE([serial-tests subdir-objects])
+ AC_CONFIG_HEADERS(config.h)
+ 
+ AC_PROG_CXX
++AC_SYS_LARGEFILE
+ 
+ AC_C_BIGENDIAN(
+     AC_DEFINE(IS_BIG_ENDIAN, 1, Big endian),
+@@ -37,8 +38,6 @@ RAK_DISABLE_BACKTRACE
+ 
+ RAK_CHECK_CXX11
+ 
+-AC_SYS_LARGEFILE
+-
+ TORRENT_ENABLE_ALIGNED
+ TORRENT_ENABLE_INTERRUPT_SOCKET
+ 
+diff --git a/src/Makefile.am b/src/Makefile.am
+index e96bd74b..95e6a7ae 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,7 +1,8 @@
+ SUBDIRS = torrent
+ 
+ lib_LTLIBRARIES = libtorrent.la
+-noinst_LTLIBRARIES = libtorrent_other.la
++noinst_LTLIBRARIES = \
++	libtorrent_other.la
+ 
+ libtorrent_la_LDFLAGS = -version-info $(LIBTORRENT_INTERFACE_VERSION_INFO)
+ libtorrent_la_LIBADD = \
+diff --git a/src/manager.h b/src/manager.h
+index 1db81e9b..1ada9567 100644
+--- a/src/manager.h
++++ b/src/manager.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_MANAGER_H
+ #define LIBTORRENT_MANAGER_H
+ 
+diff --git a/src/thread_disk.h b/src/thread_disk.h
+index fa1fcb7e..7b378915 100644
+--- a/src/thread_disk.h
++++ b/src/thread_disk.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_THREAD_DISK_H
+ #define LIBTORRENT_THREAD_DISK_H
+ 
+@@ -42,19 +6,18 @@
+ 
+ namespace torrent {
+ 
+-class thread_disk : public thread_base {
++class LIBTORRENT_EXPORT thread_disk : public thread_base {
+ public:
+-  const char*         name() const { return "rtorrent disk"; }
+-
+-  virtual void        init_thread();
++  const char*     name() const { return "rtorrent disk"; }
++  HashCheckQueue* hash_queue() { return &m_hash_queue; }
+ 
+-  HashCheckQueue*     hash_queue() { return &m_hash_queue; }
++  virtual void    init_thread();
+ 
+ protected:
+-  virtual void        call_events();
+-  virtual int64_t     next_timeout_usec();
++  virtual void    call_events();
++  virtual int64_t next_timeout_usec();
+ 
+-  HashCheckQueue      m_hash_queue;
++  HashCheckQueue  m_hash_queue;
+ };
+ 
+ }
+diff --git a/src/torrent/utils/thread_base.cc b/src/torrent/utils/thread_base.cc
+index 778e4c38..99d6355d 100644
+--- a/src/torrent/utils/thread_base.cc
++++ b/src/torrent/utils/thread_base.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"
+ 
+ #include <cstring>
+diff --git a/src/torrent/utils/thread_base.h b/src/torrent/utils/thread_base.h
+index b92a98ba..bead9659 100644
+--- a/src/torrent/utils/thread_base.h
++++ b/src/torrent/utils/thread_base.h
+@@ -1,48 +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_UTILS_THREAD_BASE_H
+ #define LIBTORRENT_UTILS_THREAD_BASE_H
+ 
+-#include <functional>
+-#include <pthread.h>
+-#include <sys/types.h>
++#import <functional>
++#import <pthread.h>
++#import <sys/types.h>
+ 
+-#include <torrent/common.h>
+-#include <torrent/utils/signal_bitfield.h>
++#import <torrent/common.h>
++#import <torrent/utils/signal_bitfield.h>
+ 
+ namespace torrent {
+ 
+@@ -54,7 +18,7 @@ public:
+   typedef void* (*pthread_func)(void*);
+   typedef std::function<void ()>     slot_void;
+   typedef std::function<uint64_t ()> slot_timer;
+-  typedef class signal_bitfield           signal_type;
++  typedef class signal_bitfield      signal_type;
+ 
+   enum state_type {
+     STATE_UNKNOWN,
+diff --git a/test/Makefile.am b/test/Makefile.am
+index 8b0291bb..cb00dce3 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -1,6 +1,10 @@
+ TESTS = \
+ 	LibTorrent_Test_Torrent_Net \
++	LibTorrent_Test_Torrent_Utils \
++	LibTorrent_Test_Torrent \
++	LibTorrent_Test_Data \
+ 	LibTorrent_Test_Net \
++	LibTorrent_Test_Tracker \
+ 	LibTorrent_Test
+ 
+ check_PROGRAMS = $(TESTS)
+@@ -10,22 +14,14 @@ LibTorrent_Test_LDADD = \
+ 	../src/libtorrent_other.la \
+ 	../src/torrent/libtorrent_torrent.la
+ 
+-LibTorrent_Test_Net_LDADD = $(LibTorrent_Test_LDADD)
+ LibTorrent_Test_Torrent_Net_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Torrent_Utils_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Torrent_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Data_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Net_LDADD = $(LibTorrent_Test_LDADD)
++LibTorrent_Test_Tracker_LDADD = $(LibTorrent_Test_LDADD)
+ 
+-# LibTorrent_Test_SOURCES = \
+-# 	helpers/expect_fd.h \
+-# 	helpers/expect_utils.h \
+-# 	helpers/mock_compare.h \
+-# 	helpers/mock_function.cc \
+-# 	helpers/mock_function.h \
+-# 	helpers/network.h \
+-# 	helpers/progress_listener.cc \
+-# 	helpers/progress_listener.h \
+-# 	helpers/test_fixture.cc \
+-# 	helpers/test_fixture.h
+-
+-LibTorrent_Test_Torrent_Net_SOURCES = \
++LibTorrent_Test_Common = \
+ 	main.cc \
+ 	helpers/expect_fd.h \
+ 	helpers/expect_utils.h \
+@@ -37,7 +33,10 @@ LibTorrent_Test_Torrent_Net_SOURCES = \
+ 	helpers/progress_listener.h \
+ 	helpers/test_fixture.cc \
+ 	helpers/test_fixture.h \
+-	\
++	helpers/test_thread.cc \
++	helpers/test_thread.h
++
++LibTorrent_Test_Torrent_Net_SOURCES = $(LibTorrent_Test_Common) \
+ 	torrent/net/test_address_info.cc \
+ 	torrent/net/test_address_info.h \
+ 	torrent/net/test_fd.cc \
+@@ -45,71 +44,28 @@ LibTorrent_Test_Torrent_Net_SOURCES = \
+ 	torrent/net/test_socket_address.cc \
+ 	torrent/net/test_socket_address.h
+ 
+-LibTorrent_Test_Net_SOURCES = \
+-	main.cc \
+-	helpers/expect_fd.h \
+-	helpers/expect_utils.h \
+-	helpers/mock_compare.h \
+-	helpers/mock_function.cc \
+-	helpers/mock_function.h \
+-	helpers/network.h \
+-	helpers/progress_listener.cc \
+-	helpers/progress_listener.h \
+-	helpers/test_fixture.cc \
+-	helpers/test_fixture.h \
+-	\
+-	net/test_socket_listen.cc \
+-	net/test_socket_listen.h
+-
+-LibTorrent_Test_SOURCES = \
+-	main.cc \
+-	helpers/expect_fd.h \
+-	helpers/expect_utils.h \
+-	helpers/mock_compare.h \
+-	helpers/mock_function.cc \
+-	helpers/mock_function.h \
+-	helpers/network.h \
+-	helpers/progress_listener.cc \
+-	helpers/progress_listener.h \
+-	helpers/test_fixture.cc \
+-	helpers/test_fixture.h \
+-	\
+-	../src/thread_disk.cc \
+-	../src/thread_disk.h \
+-	\
+-	rak/allocators_test.cc \
+-	rak/allocators_test.h \
+-	rak/ranges_test.cc \
+-	rak/ranges_test.h \
+-	data/chunk_list_test.cc \
+-	data/chunk_list_test.h \
+-	data/hash_check_queue_test.cc \
+-	data/hash_check_queue_test.h \
+-	data/hash_queue_test.cc \
+-	data/hash_queue_test.h \
+-	\
+-	protocol/test_request_list.cc \
+-	protocol/test_request_list.h \
+-	\
+-	torrent/utils/log_test.cc \
+-	torrent/utils/log_test.h \
+-	torrent/utils/option_strings_test.cc \
+-	torrent/utils/option_strings_test.h \
++LibTorrent_Test_Torrent_Utils_SOURCES = $(LibTorrent_Test_Common) \
+ 	torrent/utils/test_extents.cc \
+ 	torrent/utils/test_extents.h \
++	torrent/utils/test_log.cc \
++	torrent/utils/test_log.h \
+ 	torrent/utils/test_log_buffer.cc \
+ 	torrent/utils/test_log_buffer.h \
++	torrent/utils/test_option_strings.cc \
++	torrent/utils/test_option_strings.h \
+ 	torrent/utils/test_queue_buckets.cc \
+ 	torrent/utils/test_queue_buckets.h \
++	torrent/utils/test_signal_bitfield.cc \
++	torrent/utils/test_signal_bitfield.h \
++	torrent/utils/test_thread_base.cc \
++	torrent/utils/test_thread_base.h \
+ 	torrent/utils/test_uri_parser.cc \
+-	torrent/utils/test_uri_parser.h \
+-	torrent/utils/signal_bitfield_test.cc \
+-	torrent/utils/signal_bitfield_test.h \
+-	torrent/utils/thread_base_test.cc \
+-	torrent/utils/thread_base_test.h \
++	torrent/utils/test_uri_parser.h
++
++LibTorrent_Test_Torrent_SOURCES = $(LibTorrent_Test_Common) \
++	torrent/test_http.cc \
++	torrent/test_http.h \
+ 	\
+-	torrent/http_test.cc \
+-	torrent/http_test.h \
+ 	torrent/object_test.cc \
+ 	torrent/object_test.h \
+ 	torrent/object_test_utils.cc \
+@@ -129,15 +85,49 @@ LibTorrent_Test_SOURCES = \
+ 	torrent/tracker_list_features_test.cc \
+ 	torrent/tracker_list_features_test.h \
+ 	torrent/tracker_timeout_test.cc \
+-	torrent/tracker_timeout_test.h \
++	torrent/tracker_timeout_test.h
++
++LibTorrent_Test_Data_SOURCES = $(LibTorrent_Test_Common) \
++	data/test_chunk_list.cc \
++	data/test_chunk_list.h \
++	data/test_hash_check_queue.cc \
++	data/test_hash_check_queue.h \
++	data/test_hash_queue.cc \
++	data/test_hash_queue.h
++
++LibTorrent_Test_Net_SOURCES = $(LibTorrent_Test_Common) \
++	net/test_socket_listen.cc \
++	net/test_socket_listen.h
++
++LibTorrent_Test_Tracker_SOURCES = $(LibTorrent_Test_Common) \
++	tracker/test_tracker_http.cc \
++	tracker/test_tracker_http.h
++
++LibTorrent_Test_SOURCES = $(LibTorrent_Test_Common) \
++	\
++	../src/thread_disk.cc \
++	../src/thread_disk.h \
+ 	\
+-	tracker/tracker_http_test.cc \
+-	tracker/tracker_http_test.h
++	rak/allocators_test.cc \
++	rak/allocators_test.h \
++	rak/ranges_test.cc \
++	rak/ranges_test.h \
++	\
++	protocol/test_request_list.cc \
++	protocol/test_request_list.h
+ 
+ LibTorrent_Test_Torrent_Net_CXXFLAGS = $(CPPUNIT_CFLAGS)
+ LibTorrent_Test_Torrent_Net_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Torrent_Utils_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Torrent_Utils_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Torrent_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Torrent_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Data_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Data_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+ LibTorrent_Test_Net_CXXFLAGS = $(CPPUNIT_CFLAGS)
+ LibTorrent_Test_Net_LDFLAGS = $(CPPUNIT_LIBS) -ldl
++LibTorrent_Test_Tracker_CXXFLAGS = $(CPPUNIT_CFLAGS)
++LibTorrent_Test_Tracker_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+ LibTorrent_Test_CXXFLAGS = $(CPPUNIT_CFLAGS)
+ LibTorrent_Test_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+ 
+diff --git a/test/data/chunk_list_test.cc b/test/data/test_chunk_list.cc
+similarity index 93%
+rename from test/data/chunk_list_test.cc
+rename to test/data/test_chunk_list.cc
+index 28647db2..18de597e 100644
+--- a/test/data/chunk_list_test.cc
++++ b/test/data/test_chunk_list.cc
+@@ -1,11 +1,11 @@
+-#include "config.h"
++#import "config.h"
+ 
+-#include "chunk_list_test.h"
++#import "test_chunk_list.h"
+ 
+-#include "torrent/chunk_manager.h"
+-#include "torrent/exceptions.h"
++#import "torrent/chunk_manager.h"
++#import "torrent/exceptions.h"
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(ChunkListTest);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_chunk_list, "data");
+ 
+ torrent::Chunk*
+ func_create_chunk(uint32_t index, int prot_flags) {
+@@ -36,7 +36,7 @@ func_storage_error(torrent::ChunkList* chunk_list, const std::string& message) {
+ }
+ 
+ void
+-ChunkListTest::test_basic() {
++test_chunk_list::test_basic() {
+   torrent::ChunkManager chunk_manager;
+   torrent::ChunkList chunk_list;
+ 
+@@ -55,7 +55,7 @@ ChunkListTest::test_basic() {
+ }
+ 
+ void
+-ChunkListTest::test_get_release() {
++test_chunk_list::test_get_release() {
+   SETUP_CHUNK_LIST();
+ 
+   CPPUNIT_ASSERT(!(*chunk_list)[0].is_valid());
+@@ -112,7 +112,7 @@ ChunkListTest::test_get_release() {
+ 
+ // Make sure we can't go into writable when blocking, etc.
+ void
+-ChunkListTest::test_blocking() {
++test_chunk_list::test_blocking() {
+   SETUP_CHUNK_LIST();
+ 
+   torrent::ChunkHandle handle_0_ro = chunk_list->get(0, torrent::ChunkList::get_blocking);
+diff --git a/test/data/chunk_list_test.h b/test/data/test_chunk_list.h
+similarity index 88%
+rename from test/data/chunk_list_test.h
+rename to test/data/test_chunk_list.h
+index 3979982f..85d1f77b 100644
+--- a/test/data/chunk_list_test.h
++++ b/test/data/test_chunk_list.h
+@@ -1,23 +1,22 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#import "helpers/test_fixture.h"
+ 
+-#include "data/chunk_list.h"
++class test_chunk_list : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_chunk_list);
+ 
+-class ChunkListTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(ChunkListTest);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_get_release);
+   CPPUNIT_TEST(test_blocking);
++
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp() {}
+-  void tearDown() {}
+-
+   void test_basic();
+   void test_get_release();
+   void test_blocking();
+ };
+ 
++#include "data/chunk_list.h"
++
+ torrent::Chunk* func_create_chunk(uint32_t index, int prot_flags);
+ uint64_t        func_free_diskspace(torrent::ChunkList* chunk_list);
+ void            func_storage_error(torrent::ChunkList* chunk_list, const std::string& message);
+diff --git a/test/data/hash_check_queue_test.cc b/test/data/test_hash_check_queue.cc
+similarity index 92%
+rename from test/data/hash_check_queue_test.cc
+rename to test/data/test_hash_check_queue.cc
+index 4b15245e..65931273 100644
+--- a/test/data/hash_check_queue_test.cc
++++ b/test/data/test_hash_check_queue.cc
+@@ -1,20 +1,23 @@
+ #include "config.h"
+ 
++#include "test_hash_check_queue.h"
++
++#include "helpers/test_thread.h"
++#include "helpers/test_utils.h"
++
+ #include <functional>
+ #include <signal.h>
+ 
+-#include "data/hash_queue_node.h"
++#include "data/chunk_handle.h"
+ #include "utils/sha1.h"
+ #include "torrent/chunk_manager.h"
+ #include "torrent/exceptions.h"
+ #include "torrent/poll_select.h"
+-#include "torrent/utils/thread_base_test.h"
+ #include "thread_disk.h"
+ 
+-#include "chunk_list_test.h"
+-#include "hash_check_queue_test.h"
++#include "test_chunk_list.h"
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(HashCheckQueueTest);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_hash_check_queue, "data");
+ 
+ pthread_mutex_t done_chunks_lock = PTHREAD_MUTEX_INITIALIZER;
+ 
+@@ -68,22 +71,16 @@ static torrent::Poll* create_select_poll() { return torrent::PollSelect::create(
+ static void do_nothing() {}
+ 
+ void
+-HashCheckQueueTest::setUp() {
++test_hash_check_queue::setUp() {
++  test_fixture::setUp();
++
+   torrent::Poll::slot_create_poll() = std::bind(&create_select_poll);
+ 
+   signal(SIGUSR1, (sig_t)&do_nothing);
+ }
+ 
+ void
+-HashCheckQueueTest::tearDown() {
+-}
+-
+-void
+-HashCheckQueueTest::test_basic() {
+-}
+-
+-void
+-HashCheckQueueTest::test_single() {
++test_hash_check_queue::test_single() {
+   SETUP_CHUNK_LIST();
+   torrent::HashCheckQueue hash_queue;
+ 
+@@ -110,7 +107,7 @@ HashCheckQueueTest::test_single() {
+ }
+ 
+ void
+-HashCheckQueueTest::test_multiple() {
++test_hash_check_queue::test_multiple() {
+   SETUP_CHUNK_LIST();
+   torrent::HashCheckQueue hash_queue;
+ 
+@@ -143,7 +140,7 @@ HashCheckQueueTest::test_multiple() {
+ }
+ 
+ void
+-HashCheckQueueTest::test_erase() {
++test_hash_check_queue::test_erase() {
+   // SETUP_CHUNK_LIST();
+   // torrent::HashCheckQueue hash_queue;
+ 
+@@ -176,7 +173,7 @@ HashCheckQueueTest::test_erase() {
+ }
+ 
+ void
+-HashCheckQueueTest::test_thread() {
++test_hash_check_queue::test_thread() {
+   SETUP_CHUNK_LIST();
+   SETUP_THREAD();
+   thread_disk->start_thread();
+diff --git a/test/data/hash_check_queue_test.h b/test/data/test_hash_check_queue.h
+similarity index 63%
+rename from test/data/hash_check_queue_test.h
+rename to test/data/test_hash_check_queue.h
+index 5398a50d..d2d271bb 100644
+--- a/test/data/hash_check_queue_test.h
++++ b/test/data/test_hash_check_queue.h
+@@ -1,26 +1,19 @@
+-#include <map>
+-#include <vector>
+-#include <cppunit/extensions/HelperMacros.h>
++#import "helpers/test_fixture.h"
+ 
+-#include "data/hash_check_queue.h"
+-#include "torrent/hash_string.h"
++class test_hash_check_queue : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_hash_check_queue);
+ 
+-
+-class HashCheckQueueTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(HashCheckQueueTest);
+-  CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_single);
+   CPPUNIT_TEST(test_multiple);
+   CPPUNIT_TEST(test_erase);
+ 
+   CPPUNIT_TEST(test_thread);
++
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+   void setUp();
+-  void tearDown();
+ 
+-  void test_basic();
+   void test_single();
+   void test_multiple();
+   void test_erase();
+@@ -28,6 +21,13 @@ public:
+   void test_thread();
+ };
+ 
++#import <map>
++#import <vector>
++
++#import "data/hash_queue_node.h"
++#import "data/hash_check_queue.h"
++#import "torrent/hash_string.h"
++
+ typedef std::map<int, torrent::HashString> done_chunks_type;
+ typedef std::vector<torrent::ChunkHandle> handle_list;
+ 
+diff --git a/test/data/hash_queue_test.cc b/test/data/test_hash_queue.cc
+similarity index 82%
+rename from test/data/hash_queue_test.cc
+rename to test/data/test_hash_queue.cc
+index d7ce3ba8..d9a88c8d 100644
+--- a/test/data/hash_queue_test.cc
++++ b/test/data/test_hash_queue.cc
+@@ -1,22 +1,26 @@
+-#include "config.h"
++#import "config.h"
+ 
+-#include <functional>
+-#include <signal.h>
++#import "test_hash_queue.h"
+ 
+-#include "data/hash_queue_node.h"
+-#include "torrent/chunk_manager.h"
+-#include "torrent/exceptions.h"
+-#include "torrent/hash_string.h"
+-#include "torrent/poll_select.h"
+-#include "torrent/utils/thread_base_test.h"
+-#include "globals.h"
+-#include "thread_disk.h"
++#import "helpers/test_thread.h"
++#import "helpers/test_utils.h"
+ 
+-#include "chunk_list_test.h"
+-#include "hash_queue_test.h"
+-#include "hash_check_queue_test.h"
++#import <functional>
++#import <signal.h>
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(HashQueueTest);
++#import "data/hash_queue.h"
++#import "data/hash_queue_node.h"
++#import "torrent/chunk_manager.h"
++#import "torrent/exceptions.h"
++#import "torrent/hash_string.h"
++#import "torrent/poll_select.h"
++#import "globals.h"
++#import "thread_disk.h"
++
++#import "test_chunk_list.h"
++#import "test_hash_check_queue.h"
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_hash_queue, "data");
+ 
+ typedef std::map<int, torrent::HashString> done_chunks_type;
+ 
+@@ -39,7 +43,9 @@ static torrent::Poll* create_select_poll() { return torrent::PollSelect::create(
+ static void do_nothing() {}
+ 
+ void
+-HashQueueTest::setUp() {
++test_hash_queue::setUp() {
++  test_fixture::setUp();
++
+   CPPUNIT_ASSERT(torrent::taskScheduler.empty());
+ 
+   torrent::Poll::slot_create_poll() = std::bind(&create_select_poll);
+@@ -47,25 +53,9 @@ HashQueueTest::setUp() {
+ }
+ 
+ void
+-HashQueueTest::tearDown() {
++test_hash_queue::tearDown() {
+   torrent::taskScheduler.clear();
+-}
+-
+-void
+-HashQueueTest::test_basic() {
+-  // SETUP_CHUNK_LIST();
+-  // SETUP_THREAD();
+-  // thread_disk->start_thread();
+-
+-  // torrent::HashQueue* hash_queue = new torrent::HashQueue(thread_disk);
+-  
+-  // // Do stuff?
+-
+-  // delete hash_queue;
+-
+-  // thread_disk->stop_thread();
+-  // CLEANUP_THREAD();
+-  // CLEANUP_CHUNK_LIST();
++  test_fixture::tearDown();
+ }
+ 
+ static void
+@@ -73,7 +63,7 @@ fill_queue() {
+ }
+ 
+ void
+-HashQueueTest::test_single() {
++test_hash_queue::test_single() {
+   SETUP_CHUNK_LIST();
+   SETUP_THREAD();
+   thread_disk->start_thread();
+@@ -105,7 +95,7 @@ HashQueueTest::test_single() {
+ }
+ 
+ void
+-HashQueueTest::test_multiple() {
++test_hash_queue::test_multiple() {
+   SETUP_CHUNK_LIST();
+   SETUP_THREAD();
+   thread_disk->start_thread();
+@@ -137,7 +127,7 @@ HashQueueTest::test_multiple() {
+ }
+ 
+ void
+-HashQueueTest::test_erase() {
++test_hash_queue::test_erase() {
+   SETUP_CHUNK_LIST();
+   SETUP_THREAD();
+ 
+@@ -164,7 +154,7 @@ HashQueueTest::test_erase() {
+ }
+ 
+ void
+-HashQueueTest::test_erase_stress() {
++test_hash_queue::test_erase_stress() {
+   SETUP_CHUNK_LIST();
+   SETUP_THREAD();
+   thread_disk->start_thread();
+diff --git a/test/data/hash_queue_test.h b/test/data/test_hash_queue.h
+similarity index 58%
+rename from test/data/hash_queue_test.h
+rename to test/data/test_hash_queue.h
+index cb5b7282..79914484 100644
+--- a/test/data/hash_queue_test.h
++++ b/test/data/test_hash_queue.h
+@@ -1,10 +1,7 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#include "helpers/test_fixture.h"
+ 
+-#include "data/hash_queue.h"
+-
+-class HashQueueTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(HashQueueTest);
+-  CPPUNIT_TEST(test_basic);
++class test_hash_queue : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_hash_queue);
+ 
+   CPPUNIT_TEST(test_single);
+   CPPUNIT_TEST(test_multiple);
+@@ -17,8 +14,6 @@ public:
+   void setUp();
+   void tearDown();
+ 
+-  void test_basic();
+-
+   void test_single();
+   void test_multiple();
+   void test_erase();
+diff --git a/test/helpers/progress_listener.cc b/test/helpers/progress_listener.cc
+index c2b60bcd..7a6ed047 100644
+--- a/test/helpers/progress_listener.cc
++++ b/test/helpers/progress_listener.cc
+@@ -36,10 +36,10 @@ progress_listener::addFailure(const CppUnit::TestFailure &failure) {
+   if (m_current_log_buffer == nullptr)
+     return;
+ 
+-  std::cout << " : " << (failure.isError() ? "error" : "assertion");
++  std::cout << " : " << (failure.isError() ? "error" : "assertion") << std::flush;
+ 
+   m_last_test_failed = true;
+-  m_failures.push_back(std::move(failure_type{failure.failedTestName(), std::move(m_current_log_buffer)}));
++  m_failures.push_back(failure_type{ failure.failedTestName(), std::move(m_current_log_buffer) });
+ }
+ 
+ void
+diff --git a/test/helpers/test_fixture.h b/test/helpers/test_fixture.h
+index 312d5009..aa557a5e 100644
+--- a/test/helpers/test_fixture.h
++++ b/test/helpers/test_fixture.h
+@@ -1,14 +1,14 @@
+-#ifndef LIBTORRENT_HELPER_TEST_FIXTURE_H
+-#define LIBTORRENT_HELPER_TEST_FIXTURE_H
+-
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "helpers/mock_function.h"
+-
+-class test_fixture : public CppUnit::TestFixture {
+-public:
+-  void setUp();
+-  void tearDown();
+-};
+-
+-#endif
++#ifndef LIBTORRENT_HELPER_TEST_FIXTURE_H
++#define LIBTORRENT_HELPER_TEST_FIXTURE_H
++
++#include <cppunit/extensions/HelperMacros.h>
++
++#include "helpers/mock_function.h"
++
++class test_fixture : public CppUnit::TestFixture {
++public:
++  void setUp();
++  void tearDown();
++};
++
++#endif
+diff --git a/test/helpers/test_thread.cc b/test/helpers/test_thread.cc
+new file mode 100755
+index 00000000..4b3d4c95
+--- /dev/null
++++ b/test/helpers/test_thread.cc
+@@ -0,0 +1,71 @@
++#import "config.h"
++
++#import "test_thread.h"
++
++#import <unistd.h>
++#import <cppunit/extensions/HelperMacros.h>
++
++#import "thread_disk.h"
++#import "torrent/exceptions.h"
++#import "torrent/poll_select.h"
++
++const int test_thread::test_flag_pre_stop;
++const int test_thread::test_flag_long_timeout;
++
++const int test_thread::test_flag_acquire_global;
++const int test_thread::test_flag_has_global;
++
++const int test_thread::test_flag_do_work;
++const int test_thread::test_flag_pre_poke;
++const int test_thread::test_flag_post_poke;
++
++test_thread::test_thread() :
++  m_test_state(TEST_NONE),
++  m_test_flags(0) {
++}
++
++void
++test_thread::init_thread() {
++  m_state = STATE_INITIALIZED;
++  m_test_state = TEST_PRE_START;
++  m_poll = torrent::PollSelect::create(256);
++}
++
++void
++test_thread::call_events() {
++  if ((m_test_flags & test_flag_pre_stop) && m_test_state == TEST_PRE_START && m_state == STATE_ACTIVE)
++    __sync_lock_test_and_set(&m_test_state, TEST_PRE_STOP);
++
++  if ((m_test_flags & test_flag_acquire_global)) {
++    acquire_global_lock();
++    __sync_and_and_fetch(&m_test_flags, ~test_flag_acquire_global);
++    __sync_or_and_fetch(&m_test_flags, test_flag_has_global);
++  }
++
++  if ((m_flags & flag_do_shutdown)) {
++    if ((m_flags & flag_did_shutdown))
++      throw torrent::internal_error("Already trigged shutdown.");
++
++    __sync_or_and_fetch(&m_flags, flag_did_shutdown);
++    throw torrent::shutdown_exception();
++  }
++
++  if ((m_test_flags & test_flag_pre_poke)) {
++  }
++
++  if ((m_test_flags & test_flag_do_work)) {
++    usleep(10 * 1000); // TODO: Don't just sleep, as that give up core.
++    __sync_and_and_fetch(&m_test_flags, ~test_flag_do_work);
++  }
++
++  if ((m_test_flags & test_flag_post_poke)) {
++  }
++}
++
++thread_management_type::thread_management_type() {
++  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++}
++
++thread_management_type::~thread_management_type() {
++  torrent::thread_base::release_global_lock();
++}
+diff --git a/test/helpers/test_thread.h b/test/helpers/test_thread.h
+new file mode 100755
+index 00000000..52037036
+--- /dev/null
++++ b/test/helpers/test_thread.h
+@@ -0,0 +1,59 @@
++#import "torrent/utils/thread_base.h"
++
++class test_thread : public torrent::thread_base {
++public:
++  enum test_state {
++    TEST_NONE,
++    TEST_PRE_START,
++    TEST_PRE_STOP,
++    TEST_STOP
++  };
++
++  static const int test_flag_pre_stop       = 0x1;
++  static const int test_flag_long_timeout   = 0x2;
++
++  static const int test_flag_acquire_global = 0x10;
++  static const int test_flag_has_global     = 0x20;
++
++  static const int test_flag_do_work   = 0x100;
++  static const int test_flag_pre_poke  = 0x200;
++  static const int test_flag_post_poke = 0x400;
++
++  test_thread();
++
++  int     test_state() const { return m_test_state; }
++  bool    is_state(int state) const { return m_state == state; }
++  bool    is_test_state(int state) const { return m_test_state == state; }
++  bool    is_test_flags(int flags) const { return (m_test_flags & flags) == flags; }
++  bool    is_not_test_flags(int flags) const { return !(m_test_flags & flags); }
++
++  auto    name() const -> const char* { return "test_thread"; }
++
++  void    init_thread();
++
++  void    set_pre_stop() { __sync_or_and_fetch(&m_test_flags, test_flag_pre_stop); }
++  void    set_acquire_global() { __sync_or_and_fetch(&m_test_flags, test_flag_acquire_global); }
++
++  void    set_test_flag(int flags) { __sync_or_and_fetch(&m_test_flags, flags); }
++
++private:
++  void    call_events();
++  int64_t next_timeout_usec() { return (m_test_flags & test_flag_long_timeout) ? (10000 * 1000) : (100 * 1000); }
++
++  int     m_test_state lt_cacheline_aligned;
++  int     m_test_flags lt_cacheline_aligned;
++};
++
++struct thread_management_type {
++  thread_management_type();
++  ~thread_management_type();
++};
++
++#define SETUP_THREAD()                                                  \
++  thread_management_type thread_management;                             \
++  torrent::thread_disk* thread_disk = new torrent::thread_disk();       \
++  thread_disk->init_thread();
++
++#define CLEANUP_THREAD()                                                \
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&torrent::thread_base::is_inactive, thread_disk))); \
++  delete thread_disk;
+diff --git a/test/helpers/test_utils.h b/test/helpers/test_utils.h
+new file mode 100644
+index 00000000..0c8c6b7a
+--- /dev/null
++++ b/test/helpers/test_utils.h
+@@ -0,0 +1,16 @@
++#include <functional>
++#include <unistd.h>
++
++inline bool
++wait_for_true(std::function<bool ()> test_function) {
++  int i = 100;
++
++  do {
++    if (test_function())
++      return true;
++
++    usleep(10 * 1000);
++  } while (--i);
++
++  return false;
++}
+diff --git a/test/helpers/utils.h b/test/helpers/utils.h
+index d18450c1..e81d22eb 100644
+--- a/test/helpers/utils.h
++++ b/test/helpers/utils.h
+@@ -1,60 +1,60 @@
+-#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
++#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 e8a00e1f..57ae31a2 100644
+--- a/test/main.cc
++++ b/test/main.cc
+@@ -19,9 +19,11 @@
+ #include "helpers/progress_listener.h"
+ #include "helpers/utils.h"
+ 
+-CPPUNIT_REGISTRY_ADD_TO_DEFAULT("net");
+ 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("net");
++CPPUNIT_REGISTRY_ADD_TO_DEFAULT("tracker");
+ 
+ void
+ do_test_panic(int signum) {
+diff --git a/test/torrent/http_test.cc b/test/torrent/test_http.cc
+similarity index 94%
+rename from test/torrent/http_test.cc
+rename to test/torrent/test_http.cc
+index 27e04552..24ec97b5 100644
+--- a/test/torrent/http_test.cc
++++ b/test/torrent/test_http.cc
+@@ -1,10 +1,11 @@
+ #include "config.h"
+ 
+-#include <sstream>
++#include "test_http.h"
+ 
+-#include "http_test.h"
++#include <sstream>
++#include "torrent/http.h"
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(HttpTest);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_http, "torrent");
+ 
+ #define HTTP_SETUP()                                                    \
+   bool http_destroyed = false;                                          \
+@@ -72,7 +73,7 @@ TestHttp* create_test_http() { return new TestHttp; }
+ static void increment_value(int* value) { (*value)++; }
+ 
+ void
+-HttpTest::test_basic() {
++test_http::test_basic() {
+   torrent::Http::slot_factory() = std::bind(&create_test_http);
+ 
+   torrent::Http* http = torrent::Http::slot_factory()();
+@@ -94,7 +95,7 @@ HttpTest::test_basic() {
+ }
+ 
+ void
+-HttpTest::test_done() {
++test_http::test_done() {
+   HTTP_SETUP();
+   http->start();
+ 
+@@ -106,7 +107,7 @@ HttpTest::test_done() {
+ }
+ 
+ void
+-HttpTest::test_failure() {
++test_http::test_failure() {
+   HTTP_SETUP();
+   http->start();
+ 
+@@ -118,7 +119,7 @@ HttpTest::test_failure() {
+ }
+ 
+ void
+-HttpTest::test_delete_on_done() {
++test_http::test_delete_on_done() {
+   HTTP_SETUP();
+   http->start();
+   http->set_delete_stream();
+@@ -145,7 +146,7 @@ HttpTest::test_delete_on_done() {
+ }
+ 
+ void
+-HttpTest::test_delete_on_failure() {
++test_http::test_delete_on_failure() {
+   HTTP_SETUP();
+   http->start();
+   http->set_delete_stream();
+diff --git a/test/torrent/http_test.h b/test/torrent/test_http.h
+similarity index 63%
+rename from test/torrent/http_test.h
+rename to test/torrent/test_http.h
+index c6c97d08..f4334646 100644
+--- a/test/torrent/http_test.h
++++ b/test/torrent/test_http.h
+@@ -1,21 +1,18 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#import "helpers/test_fixture.h"
+ 
+-#include "torrent/http.h"
++class test_http : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_http);
+ 
+-class HttpTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(HttpTest);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_done);
+   CPPUNIT_TEST(test_failure);
+ 
+   CPPUNIT_TEST(test_delete_on_done);
+   CPPUNIT_TEST(test_delete_on_failure);
++
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp() {}
+-  void tearDown() {}
+-
+   void test_basic();
+   void test_done();
+   void test_failure();
+diff --git a/test/torrent/utils/option_strings_test.h b/test/torrent/utils/option_strings_test.h
+deleted file mode 100644
+index 55df4f19..00000000
+--- a/test/torrent/utils/option_strings_test.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "torrent/utils/option_strings.h"
+-
+-class option_strings_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(option_strings_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST(test_entries);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp() {}
+-  void tearDown() {}
+-
+-  void test_basic();
+-  void test_entries();
+-};
+diff --git a/test/torrent/utils/signal_bitfield_test.h b/test/torrent/utils/signal_bitfield_test.h
+deleted file mode 100644
+index 4590de41..00000000
+--- a/test/torrent/utils/signal_bitfield_test.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "torrent/utils/signal_bitfield.h"
+-
+-class utils_signal_bitfield_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(utils_signal_bitfield_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST(test_single);
+-  CPPUNIT_TEST(test_multiple);
+-
+-  CPPUNIT_TEST(test_thread);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp();
+-  void tearDown();
+-
+-  void test_basic();
+-  void test_single();
+-  void test_multiple();
+-
+-  void test_thread();
+-};
+diff --git a/test/torrent/utils/test_extents.cc b/test/torrent/utils/test_extents.cc
+index 87424d62..8e614e10 100644
+--- a/test/torrent/utils/test_extents.cc
++++ b/test/torrent/utils/test_extents.cc
+@@ -2,34 +2,25 @@
+ 
+ #include "test_extents.h"
+ 
+-#include <cinttypes>
+-#include <iostream>
+ #include <torrent/utils/extents.h>
++#include <torrent/utils/log.h>
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(ExtentsTest);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_extents, "torrent/utils");
+ 
+-void
+-ExtentsTest::setUp() {
+-}
++#define TEST_EXTENT_BEGIN(name)                                 \
++  lt_log_print(torrent::LOG_MOCK_CALLS, "extent: %s", name);
+ 
+-void
+-ExtentsTest::tearDown() {
+-}
+-
+-//typedef torrent::extents<uint32_t, int, 8, 16, 4> extent_type_1;
+ typedef torrent::extents<uint32_t, int> extent_type_1;
+ 
+-// typedef torrent::extents<uint32_t, int, 0, 256, 16> extent_type_3;
+-/*
+ template <typename Extent>
+ bool
+ verify_extent_data(Extent& extent, const uint32_t* idx, const int* val) {
+   while (*idx != *(idx + 1)) {
+-    if (!extent.is_equal_range(*idx, *(idx + 1) - 1, *val)) {
+-      // std::cout << *idx << ' ' << *(idx + 1) << ' ' << *val << std::endl;
+-      // std::cout << extent.at(*idx) << std::endl;
+-      // std::cout << extent.at(*(idx + 1)) << std::endl;
+-      return false;
++    for (auto i = *idx; i != *(idx + 1); i++) {
++      lt_log_print(torrent::LOG_MOCK_CALLS, "extent: at %u", i);
++
++      if (extent.at(i) != *val)
++        return false;
+     }
+ 
+     idx++;
+@@ -40,34 +31,32 @@ verify_extent_data(Extent& extent, const uint32_t* idx, const int* val) {
+ }
+ 
+ static const uint32_t idx_empty[] = {0, 256, 256};
+-static const int      val_empty[] = {0, 1};
++static const int      val_empty[] = {0};
+ 
+ static const uint32_t idx_basic_1[] = {0, 1, 255, 256, 256};
+ static const int      val_basic_1[] = {1, 0, 1};
+ 
+-// static const uint32_t idx_basic_2[] = {0, 1, 16, 255, 256, 256};
+-// static const int      val_basic_2[] = {1, 0, 2, 1};
+-*/
+ void
+-ExtentsTest::test_basic() {
++test_extents::test_basic() {
+   extent_type_1 extent_1;
+-/*
+-  // Test empty.
+-  CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_empty, val_empty));
+-
+-  CPPUNIT_ASSERT(extent_1.at(0) == int());
+-  CPPUNIT_ASSERT(extent_1.at(255) == int());
++  extent_1.insert(0, 255, int());
+ 
+-  extent_1.insert(0, 0, 1);
+-  extent_1.insert(255, 0, 1);
++  { TEST_EXTENT_BEGIN("empty");
++    CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_empty, val_empty));
+ 
+-  CPPUNIT_ASSERT(extent_1.at(0) == 1);
+-  CPPUNIT_ASSERT(extent_1.at(255) == 1);
++    CPPUNIT_ASSERT(extent_1.at(0) == int());
++    CPPUNIT_ASSERT(extent_1.at(255) == int());
++  };
++  { TEST_EXTENT_BEGIN("borders");
+ 
+-  CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_basic_1, val_basic_1));
++    extent_1.insert(0, 0, 1);
++    extent_1.insert(255, 255, 1);
++    // This step shouldn't be needed.
++    extent_1.insert(1, 254, int());
+ 
+-  // extent_1.insert(38, 3, 2);
++    CPPUNIT_ASSERT(extent_1.at(0) == 1);
++    CPPUNIT_ASSERT(extent_1.at(255) == 1);
+ 
+-  // CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_basic_2, val_basic_2));
+-*/
++    CPPUNIT_ASSERT(verify_extent_data(extent_1, idx_basic_1, val_basic_1));
++  };
+ }
+diff --git a/test/torrent/utils/test_extents.h b/test/torrent/utils/test_extents.h
+index fd790cf8..e187f6a7 100644
+--- a/test/torrent/utils/test_extents.h
++++ b/test/torrent/utils/test_extents.h
+@@ -1,13 +1,10 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#include "helpers/test_fixture.h"
+ 
+-class ExtentsTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(ExtentsTest);
++class test_extents : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_extents);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp();
+-  void tearDown();
+-
+   void test_basic();
+ };
+diff --git a/test/torrent/utils/log_test.cc b/test/torrent/utils/test_log.cc
+similarity index 92%
+rename from test/torrent/utils/log_test.cc
+rename to test/torrent/utils/test_log.cc
+index 8cc00ef8..fec7e505 100644
+--- a/test/torrent/utils/log_test.cc
++++ b/test/torrent/utils/test_log.cc
+@@ -1,5 +1,7 @@
+ #include "config.h"
+ 
++#include "test_log.h"
++
+ #include <algorithm>
+ #include <cstring>
+ #include <fstream>
+@@ -9,15 +11,13 @@
+ #include <torrent/exceptions.h>
+ #include <torrent/utils/log.h>
+ 
+-#include "log_test.h"
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_log, "torrent/utils");
+ 
+ namespace torrent {
+ typedef std::vector<std::pair<std::string, log_slot> > log_output_list;
+ extern log_output_list log_outputs;
+ }
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(utils_log_test);
+-
+ const char* expected_output = NULL;
+ unsigned int output_mask;
+ 
+@@ -35,19 +35,19 @@ test_output(const char* output, unsigned int length, unsigned int mask) {
+   CPPUNIT_ASSERT(output_mask == (mask));
+ 
+ void
+-utils_log_test::setUp() {
++test_log::setUp() {
+   // Don't initialize since this creates the group->child connections.
+   //  torrent::log_initialize();
+   torrent::log_cleanup();
+ }
+ 
+ void
+-utils_log_test::tearDown() {
++test_log::tearDown() {
+   torrent::log_cleanup();
+ }
+ 
+ void
+-utils_log_test::test_basic() {
++test_log::test_basic() {
+   CPPUNIT_ASSERT(!torrent::log_groups.empty());
+   CPPUNIT_ASSERT(torrent::log_groups.size() == torrent::LOG_GROUP_MAX_SIZE);
+ 
+@@ -61,7 +61,7 @@ open_output(const char* name, int mask = 0) {
+ }
+ 
+ void
+-utils_log_test::test_output_open() {
++test_log::test_output_open() {
+   CPPUNIT_ASSERT(torrent::log_groups[0].size_outputs() == 0);
+ 
+   // Add test for unknown output names.
+@@ -92,7 +92,7 @@ utils_log_test::test_output_open() {
+ // on unused log items.
+ 
+ void
+-utils_log_test::test_print() {
++test_log::test_print() {
+   open_output("test_print_1", 0x1);
+   open_output("test_print_2", 0x2);
+   torrent::log_add_group_output(0, "test_print_1");
+@@ -113,7 +113,7 @@ enum {
+ };
+ 
+ void
+-utils_log_test::test_children() {
++test_log::test_children() {
+   open_output("test_children_1", 0x1);
+   open_output("test_children_2", 0x2);
+   torrent::log_add_group_output(GROUP_PARENT_1, "test_children_1");
+@@ -136,8 +136,8 @@ utils_log_test::test_children() {
+ }
+ 
+ void
+-utils_log_test::test_file_output() {
+-  std::string filename = "utils_log_test.XXXXXX";
++test_log::test_file_output() {
++  std::string filename = "test_log.XXXXXX";
+ 
+   mktemp(&*filename.begin());
+ 
+@@ -159,8 +159,8 @@ utils_log_test::test_file_output() {
+ }
+ 
+ void
+-utils_log_test::test_file_output_append() {
+-  std::string filename = "utils_log_test.XXXXXX";
++test_log::test_file_output_append() {
++  std::string filename = "test_log.XXXXXX";
+ 
+   mktemp(&*filename.begin());
+ 
+diff --git a/test/torrent/utils/log_test.h b/test/torrent/utils/test_log.h
+similarity index 71%
+rename from test/torrent/utils/log_test.h
+rename to test/torrent/utils/test_log.h
+index d4cb3bc6..a06c95ae 100644
+--- a/test/torrent/utils/log_test.h
++++ b/test/torrent/utils/test_log.h
+@@ -1,9 +1,7 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#include "helpers/test_fixture.h"
+ 
+-#include "torrent/utils/log.h"
+-
+-class utils_log_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(utils_log_test);
++class test_log : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_log);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_output_open);
+ 
+diff --git a/test/torrent/utils/test_log_buffer.cc b/test/torrent/utils/test_log_buffer.cc
+index a56a5365..58412750 100644
+--- a/test/torrent/utils/test_log_buffer.cc
++++ b/test/torrent/utils/test_log_buffer.cc
+@@ -7,18 +7,10 @@
+ 
+ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_log_buffer, "torrent/utils");
+ 
+-void
+-test_log_buffer::setUp() {
+-  torrent::cachedTime = rak::timer::from_seconds(1000);
+-}
+-
+-void
+-test_log_buffer::tearDown() {
+-}
+-
+ void
+ test_log_buffer::test_basic() {
+   torrent::log_buffer log;
++  torrent::cachedTime = rak::timer::from_seconds(1000);
+ 
+   log.lock();
+   CPPUNIT_ASSERT(log.empty());
+@@ -46,6 +38,7 @@ test_log_buffer::test_basic() {
+ void
+ test_log_buffer::test_timestamps() {
+   torrent::log_buffer log;
++  torrent::cachedTime = rak::timer::from_seconds(1000);
+ 
+   log.lock_and_push_log("foobar", 6, 0);
+   CPPUNIT_ASSERT(log.back().timestamp == 1000);
+diff --git a/test/torrent/utils/test_log_buffer.h b/test/torrent/utils/test_log_buffer.h
+index 290df4c1..39c6b879 100644
+--- a/test/torrent/utils/test_log_buffer.h
++++ b/test/torrent/utils/test_log_buffer.h
+@@ -2,16 +2,11 @@
+ 
+ class test_log_buffer : public test_fixture {
+   CPPUNIT_TEST_SUITE(test_log_buffer);
+-
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_timestamps);
+-
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp();
+-  void tearDown();
+-
+   void test_basic();
+   void test_timestamps();
+ };
+diff --git a/test/torrent/utils/option_strings_test.cc b/test/torrent/utils/test_option_strings.cc
+similarity index 65%
+rename from test/torrent/utils/option_strings_test.cc
+rename to test/torrent/utils/test_option_strings.cc
+index a9bdcc89..68da1d2b 100644
+--- a/test/torrent/utils/option_strings_test.cc
++++ b/test/torrent/utils/test_option_strings.cc
+@@ -1,35 +1,22 @@
+ #include "config.h"
+ 
+-#include <fstream>
+-#include <functional>
+-#include <iostream>
++#include "test_option_strings.h"
+ 
+-#include <torrent/exceptions.h>
+-#include <torrent/utils/option_strings.h>
+-
+-#include <torrent/connection_manager.h>
+-#include <torrent/object.h>
+ #include <torrent/download.h>
+-#include <torrent/download/choke_group.h>
+-#include <torrent/download/choke_queue.h>
++#include <torrent/utils/option_strings.h>
+ #include <torrent/utils/log.h>
+ 
+-#include "option_strings_test.h"
+-
+-CPPUNIT_TEST_SUITE_REGISTRATION(option_strings_test);
+-
+-void
+-option_strings_test::test_basic() {
+-  
+-}
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_option_strings, "torrent/utils");
+ 
+ #define TEST_ENTRY(group, name, value)                                  \
+-  { std::string result(torrent::option_as_string(torrent::group, value)); \
++  { lt_log_print(torrent::LOG_MOCK_CALLS, "option_string: %s", name);   \
++    std::string result(torrent::option_as_string(torrent::group, value)); \
+     CPPUNIT_ASSERT_MESSAGE("Not found '" + result + "'", result == name); \
+-    CPPUNIT_ASSERT(torrent::option_find_string(torrent::group, name) == value); }
++    CPPUNIT_ASSERT(torrent::option_find_string(torrent::group, name) == value); \
++  }
+ 
+ void
+-option_strings_test::test_entries() {
++test_option_strings::test_entries() {
+   TEST_ENTRY(OPTION_CONNECTION_TYPE, "leech", torrent::Download::CONNECTION_LEECH);
+   TEST_ENTRY(OPTION_CONNECTION_TYPE, "seed", torrent::Download::CONNECTION_SEED);
+   TEST_ENTRY(OPTION_CONNECTION_TYPE, "initial_seed", torrent::Download::CONNECTION_INITIAL_SEED);
+diff --git a/test/torrent/utils/test_option_strings.h b/test/torrent/utils/test_option_strings.h
+new file mode 100644
+index 00000000..dc86e735
+--- /dev/null
++++ b/test/torrent/utils/test_option_strings.h
+@@ -0,0 +1,10 @@
++#include "helpers/test_fixture.h"
++
++class test_option_strings : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_option_strings);
++  CPPUNIT_TEST(test_entries);
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void test_entries();
++};
+diff --git a/test/torrent/utils/test_queue_buckets.cc b/test/torrent/utils/test_queue_buckets.cc
+index a32d17e7..49d1bae6 100644
+--- a/test/torrent/utils/test_queue_buckets.cc
++++ b/test/torrent/utils/test_queue_buckets.cc
+@@ -5,7 +5,7 @@
+ #include "utils/instrumentation.h"
+ #include "utils/queue_buckets.h"
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(TestQueueBuckets);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_queue_buckets, "torrent/utils");
+ 
+ struct test_constants {
+   static const int bucket_count = 2;
+@@ -87,7 +87,7 @@ struct test_queue_bucket_compare {
+ //
+ 
+ void
+-TestQueueBuckets::test_basic() {
++test_queue_buckets::test_basic() {
+   torrent::instrumentation_initialize();
+ 
+   buckets_type buckets;
+@@ -129,7 +129,7 @@ TestQueueBuckets::test_basic() {
+ }
+ 
+ void
+-TestQueueBuckets::test_erase() {
++test_queue_buckets::test_erase() {
+   items_destroyed = 0;
+   torrent::instrumentation_initialize();
+ 
+@@ -162,7 +162,7 @@ bucket_queue_find_in_any(const buckets_type& buckets, int value) {
+ }
+ 
+ void
+-TestQueueBuckets::test_find() {
++test_queue_buckets::test_find() {
+   items_destroyed = 0;
+   torrent::instrumentation_initialize();
+ 
+@@ -183,7 +183,7 @@ TestQueueBuckets::test_find() {
+ }
+ 
+ void
+-TestQueueBuckets::test_destroy_range() {
++test_queue_buckets::test_destroy_range() {
+   items_destroyed = 0;
+   torrent::instrumentation_initialize();
+ 
+@@ -206,7 +206,7 @@ TestQueueBuckets::test_destroy_range() {
+ }
+ 
+ void
+-TestQueueBuckets::test_move_range() {
++test_queue_buckets::test_move_range() {
+   items_destroyed = 0;
+   torrent::instrumentation_initialize();
+ 
+diff --git a/test/torrent/utils/test_queue_buckets.h b/test/torrent/utils/test_queue_buckets.h
+index 94624573..a7f1c30a 100644
+--- a/test/torrent/utils/test_queue_buckets.h
++++ b/test/torrent/utils/test_queue_buckets.h
+@@ -1,21 +1,18 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#include "helpers/test_fixture.h"
+ 
+-#include "protocol/request_list.h"
++class test_queue_buckets : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_queue_buckets);
+ 
+-class TestQueueBuckets : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(TestQueueBuckets);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_erase);
+   CPPUNIT_TEST(test_find);
+ 
+   CPPUNIT_TEST(test_destroy_range);
+   CPPUNIT_TEST(test_move_range);
++
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp() {}
+-  void tearDown() {}
+-
+   void test_basic();
+   void test_erase();
+   void test_find();
+diff --git a/test/torrent/utils/signal_bitfield_test.cc b/test/torrent/utils/test_signal_bitfield.cc
+similarity index 85%
+rename from test/torrent/utils/signal_bitfield_test.cc
+rename to test/torrent/utils/test_signal_bitfield.cc
+index 34b622b3..4ecd18c0 100644
+--- a/test/torrent/utils/signal_bitfield_test.cc
++++ b/test/torrent/utils/test_signal_bitfield.cc
+@@ -1,13 +1,15 @@
+ #include "config.h"
+ 
++#include "test_signal_bitfield.h"
++
++#include "helpers/test_thread.h"
++#include "helpers/test_utils.h"
++
+ #include <torrent/exceptions.h>
+ #include <torrent/utils/signal_bitfield.h>
+ #include <torrent/utils/thread_base.h>
+ 
+-#include "signal_bitfield_test.h"
+-#include "thread_base_test.h"
+-
+-CPPUNIT_TEST_SUITE_REGISTRATION(utils_signal_bitfield_test);
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_signal_bitfield, "torrent/utils");
+ 
+ static void
+ mark_index(uint32_t* bitfield, unsigned int index) {
+@@ -20,13 +22,10 @@ check_index(uint32_t* bitfield, unsigned int index) {
+ }
+ 
+ void
+-utils_signal_bitfield_test::setUp() {
+-}
+-
+-void
+-utils_signal_bitfield_test::tearDown() {
++test_signal_bitfield::tearDown() {
+   CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+   torrent::thread_base::release_global_lock();
++  test_fixture::tearDown();
+ }
+ 
+ static bool
+@@ -54,7 +53,7 @@ verify_did_internal_error(std::function<unsigned int ()> func, bool should_throw
+                                            did_throw));
+ 
+ void
+-utils_signal_bitfield_test::test_basic() {
++test_signal_bitfield::test_basic() {
+   SETUP_SIGNAL_BITFIELD();
+ 
+   CPPUNIT_ASSERT(torrent::signal_bitfield::max_size == sizeof(torrent::signal_bitfield::bitfield_type) * 8);
+@@ -68,7 +67,7 @@ utils_signal_bitfield_test::test_basic() {
+ }
+ 
+ void
+-utils_signal_bitfield_test::test_single() {
++test_signal_bitfield::test_single() {
+   SETUP_SIGNAL_BITFIELD();
+ 
+   CPPUNIT_ASSERT(signal_bitfield.add_signal(std::bind(&mark_index, &marked_bitfield, 0)) == 0);
+@@ -86,7 +85,7 @@ utils_signal_bitfield_test::test_single() {
+ }
+ 
+ void
+-utils_signal_bitfield_test::test_multiple() {
++test_signal_bitfield::test_multiple() {
+   SETUP_SIGNAL_BITFIELD();
+ 
+   for (unsigned int i = 0; i < torrent::signal_bitfield::max_size; i++)
+@@ -106,10 +105,10 @@ utils_signal_bitfield_test::test_multiple() {
+ }
+ 
+ void
+-utils_signal_bitfield_test::test_thread() {
++test_signal_bitfield::test_threaded() {
+   uint32_t marked_bitfield = 0;
+-  thread_test* thread = new thread_test;
+-  // thread->set_test_flag(thread_test::test_flag_long_timeout);
++  test_thread* thread = new test_thread;
++  // thread->set_test_flag(test_thread::test_flag_long_timeout);
+ 
+   for (unsigned int i = 0; i < torrent::signal_bitfield::max_size; i++)
+     CPPUNIT_ASSERT(thread->signal_bitfield()->add_signal(std::bind(&mark_index, &marked_bitfield, i)) == i);
+@@ -131,7 +130,7 @@ utils_signal_bitfield_test::test_thread() {
+   }
+ 
+   thread->stop_thread();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_INACTIVE)));
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_state, thread, test_thread::STATE_INACTIVE)));
+ 
+   delete thread;
+ }
+diff --git a/test/torrent/utils/test_signal_bitfield.h b/test/torrent/utils/test_signal_bitfield.h
+new file mode 100644
+index 00000000..2d24d955
+--- /dev/null
++++ b/test/torrent/utils/test_signal_bitfield.h
+@@ -0,0 +1,22 @@
++#include "helpers/test_fixture.h"
++
++class test_signal_bitfield : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_signal_bitfield);
++
++  CPPUNIT_TEST(test_basic);
++  CPPUNIT_TEST(test_single);
++  CPPUNIT_TEST(test_multiple);
++
++  CPPUNIT_TEST(test_threaded);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void tearDown();
++
++  void test_basic();
++  void test_single();
++  void test_multiple();
++
++  void test_threaded();
++};
+diff --git a/test/torrent/utils/test_thread_base.cc b/test/torrent/utils/test_thread_base.cc
+new file mode 100644
+index 00000000..33519b7c
+--- /dev/null
++++ b/test/torrent/utils/test_thread_base.cc
+@@ -0,0 +1,169 @@
++#include "config.h"
++
++#include "test_thread_base.h"
++
++#include "helpers/test_thread.h"
++#include "helpers/test_utils.h"
++
++#include <functional>
++#include <unistd.h>
++
++#include "torrent/exceptions.h"
++#include "torrent/poll_select.h"
++#include "torrent/utils/log.h"
++#include "torrent/utils/thread_base.h"
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_thread_base, "torrent/utils");
++
++#define TEST_BEGIN(name)                                           \
++  lt_log_print(torrent::LOG_MOCK_CALLS, "thread_base: %s", name);  \
++
++void throw_shutdown_exception() { throw torrent::shutdown_exception(); }
++
++void
++test_thread_base::tearDown() {
++  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++  torrent::thread_base::release_global_lock();
++  test_fixture::tearDown();
++}
++
++void
++test_thread_base::test_basic() {
++  test_thread* thread = new test_thread;
++
++  CPPUNIT_ASSERT(thread->flags() == 0);
++
++  CPPUNIT_ASSERT(!thread->is_main_polling());
++  CPPUNIT_ASSERT(!thread->is_active());
++  CPPUNIT_ASSERT(thread->global_queue_size() == 0);
++  CPPUNIT_ASSERT(thread->poll() == NULL);
++
++  // Check active...
++}
++
++void
++test_thread_base::test_lifecycle() {
++  test_thread* thread = new test_thread;
++
++  CPPUNIT_ASSERT(thread->state() == torrent::thread_base::STATE_UNKNOWN);
++  CPPUNIT_ASSERT(thread->test_state() == test_thread::TEST_NONE);
++
++  thread->init_thread();
++  CPPUNIT_ASSERT(thread->state() == torrent::thread_base::STATE_INITIALIZED);
++  CPPUNIT_ASSERT(thread->is_initialized());
++  CPPUNIT_ASSERT(thread->test_state() == test_thread::TEST_PRE_START);
++
++  thread->set_pre_stop();
++  CPPUNIT_ASSERT(!wait_for_true(std::bind(&test_thread::is_test_state, thread, test_thread::TEST_PRE_STOP)));
++
++  thread->start_thread();
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_state, thread, test_thread::STATE_ACTIVE)));
++  CPPUNIT_ASSERT(thread->is_active());
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_test_state, thread, test_thread::TEST_PRE_STOP)));
++
++  thread->stop_thread();
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_state, thread, test_thread::STATE_INACTIVE)));
++  CPPUNIT_ASSERT(thread->is_inactive());
++
++  delete thread;
++}
++
++void
++test_thread_base::test_global_lock_basic() {
++  test_thread* thread = new test_thread;
++  
++  thread->init_thread();
++  thread->start_thread();
++  
++  CPPUNIT_ASSERT(torrent::thread_base::global_queue_size() == 0);
++
++  // Acquire main thread...
++  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
++
++  torrent::thread_base::release_global_lock();
++  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
++    
++  torrent::thread_base::release_global_lock();
++  torrent::thread_base::acquire_global_lock();
++  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
++
++  thread->set_acquire_global();
++  CPPUNIT_ASSERT(!wait_for_true(std::bind(&test_thread::is_test_flags, thread, test_thread::test_flag_has_global)));
++  
++  torrent::thread_base::release_global_lock();
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_test_flags, thread, test_thread::test_flag_has_global)));
++
++  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
++  torrent::thread_base::release_global_lock();
++  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++
++  // Test waive (loop).
++
++  CPPUNIT_ASSERT(torrent::thread_base::global_queue_size() == 0);
++
++  torrent::thread_base::release_global_lock();
++  thread->stop_thread();
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_state, thread, test_thread::STATE_INACTIVE)));
++
++  delete thread;
++}
++
++void
++test_thread_base::test_interrupt() {
++  test_thread* thread = new test_thread;
++  thread->set_test_flag(test_thread::test_flag_long_timeout);
++
++  thread->init_thread();
++  thread->start_thread();
++
++  // Vary the various timeouts.
++
++  for (int i = 0; i < 100; i++) {
++    thread->interrupt();
++    usleep(0);
++
++    thread->set_test_flag(test_thread::test_flag_do_work);
++    thread->interrupt();
++
++    // Wait for flag to clear.
++    CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_not_test_flags, thread, test_thread::test_flag_do_work)));
++  }
++
++  thread->stop_thread();
++  CPPUNIT_ASSERT(wait_for_true(std::bind(&test_thread::is_state, thread, test_thread::STATE_INACTIVE)));
++
++  delete thread;
++}
++
++void
++test_thread_base::test_stop() {
++  { TEST_BEGIN("trylock global lock");
++    CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
++    // torrent::thread_base::acquire_global_lock();
++  };
++
++  for (int i = 0; i < 20; i++) {
++    CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
++
++    test_thread* thread = new test_thread;
++    thread->set_test_flag(test_thread::test_flag_do_work);
++
++    { TEST_BEGIN("init and start thread");
++      thread->init_thread();
++      thread->start_thread();
++    };
++
++    { TEST_BEGIN("stop and delete thread");
++      thread->stop_thread_wait();
++      CPPUNIT_ASSERT(thread->is_inactive());
++
++      delete thread;
++    }
++  }
++
++  { TEST_BEGIN("release global lock");
++    torrent::thread_base::release_global_lock();
++  };
++}
+diff --git a/test/torrent/utils/test_thread_base.h b/test/torrent/utils/test_thread_base.h
+new file mode 100644
+index 00000000..7b2a3432
+--- /dev/null
++++ b/test/torrent/utils/test_thread_base.h
+@@ -0,0 +1,25 @@
++#include "helpers/test_fixture.h"
++
++class test_thread_base : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_thread_base);
++
++  CPPUNIT_TEST(test_basic);
++  CPPUNIT_TEST(test_lifecycle);
++
++  CPPUNIT_TEST(test_global_lock_basic);
++  CPPUNIT_TEST(test_interrupt);
++  CPPUNIT_TEST(test_stop);
++
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void tearDown();
++
++  void test_basic();
++  void test_lifecycle();
++
++  void test_global_lock_basic();
++  void test_interrupt();
++  void test_interrupt_legacy();
++  void test_stop();
++};
+diff --git a/test/torrent/utils/test_uri_parser.cc b/test/torrent/utils/test_uri_parser.cc
+index 1f4bebe8..66d6cda5 100644
+--- a/test/torrent/utils/test_uri_parser.cc
++++ b/test/torrent/utils/test_uri_parser.cc
+@@ -2,31 +2,22 @@
+ 
+ #include "test_uri_parser.h"
+ 
+-#include <cinttypes>
+-#include <iostream>
++#include <torrent/utils/log.h>
+ #include <torrent/utils/uri_parser.h>
+ 
+-CPPUNIT_TEST_SUITE_REGISTRATION(UriParserTest);
+-
+-void
+-UriParserTest::setUp() {
+-}
+-
+-void
+-UriParserTest::tearDown() {
+-}
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_uri_parser, "torrent/utils");
+ 
+ void
+ test_print_uri_state(torrent::utils::uri_state state) {
+-  std::cerr << "state.uri: " << state.uri << std::endl;
+-  std::cerr << "state.scheme: " << state.scheme << std::endl;
+-  std::cerr << "state.resource: " << state.resource << std::endl;
+-  std::cerr << "state.query: " << state.query << std::endl;
+-  std::cerr << "state.fragment: " << state.fragment << std::endl;
++  lt_log_print(torrent::LOG_MOCK_CALLS, "state.uri: %s", state.uri.c_str());
++  lt_log_print(torrent::LOG_MOCK_CALLS, "state.scheme: %s", state.scheme.c_str());
++  lt_log_print(torrent::LOG_MOCK_CALLS, "state.resource: %s", state.resource.c_str());
++  lt_log_print(torrent::LOG_MOCK_CALLS, "state.query: %s", state.query.c_str());
++  lt_log_print(torrent::LOG_MOCK_CALLS, "state.fragment: %s", state.fragment.c_str());
+ }
+ 
+ void
+-UriParserTest::test_basic() {
++test_uri_parser::test_basic() {
+   torrent::utils::uri_state state;
+ 
+   CPPUNIT_ASSERT(state.state == torrent::utils::uri_state::state_empty);
+@@ -37,7 +28,7 @@ UriParserTest::test_basic() {
+ #define MAGNET_BASIC "magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C"
+ 
+ void
+-UriParserTest::test_basic_magnet() {
++test_uri_parser::test_basic_magnet() {
+   torrent::utils::uri_state state;
+ 
+   uri_parse_str(MAGNET_BASIC, state);
+@@ -63,7 +54,7 @@ UriParserTest::test_basic_magnet() {
+ #define QUERY_MAGNET "magnet:?" QUERY_MAGNET_QUERY
+ 
+ void
+-UriParserTest::test_query_magnet() {
++test_uri_parser::test_query_magnet() {
+   torrent::utils::uri_state state;
+   torrent::utils::uri_query_state query_state;
+ 
+@@ -82,7 +73,7 @@ UriParserTest::test_query_magnet() {
+   uri_parse_query_str(state.query, query_state);
+   
+   for (auto element : query_state.elements)
+-    std::cerr << "query_element: " << element << std::endl;
++    lt_log_print(torrent::LOG_MOCK_CALLS, "query_element: %s", element.c_str());
+ 
+   CPPUNIT_ASSERT(query_state.state == torrent::utils::uri_query_state::state_valid);
+ 
+diff --git a/test/torrent/utils/test_uri_parser.h b/test/torrent/utils/test_uri_parser.h
+index 4f1c2586..f978c8ad 100644
+--- a/test/torrent/utils/test_uri_parser.h
++++ b/test/torrent/utils/test_uri_parser.h
+@@ -1,16 +1,15 @@
+-#include <cppunit/extensions/HelperMacros.h>
++#include "helpers/test_fixture.h"
++
++class test_uri_parser : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_uri_parser);
+ 
+-class UriParserTest : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(UriParserTest);
+   CPPUNIT_TEST(test_basic);
+   CPPUNIT_TEST(test_basic_magnet);
+   CPPUNIT_TEST(test_query_magnet);
++
+   CPPUNIT_TEST_SUITE_END();
+ 
+ public:
+-  void setUp();
+-  void tearDown();
+-
+   void test_basic();
+   void test_basic_magnet();
+   void test_query_magnet();
+diff --git a/test/torrent/utils/thread_base_test.cc b/test/torrent/utils/thread_base_test.cc
+deleted file mode 100644
+index 8366c9ba..00000000
+--- a/test/torrent/utils/thread_base_test.cc
++++ /dev/null
+@@ -1,224 +0,0 @@
+-#include "config.h"
+-
+-#include <functional>
+-#include <unistd.h>
+-
+-#include <torrent/exceptions.h>
+-#include <torrent/poll_select.h>
+-#include <torrent/utils/thread_base.h>
+-
+-#include "thread_base_test.h"
+-
+-CPPUNIT_TEST_SUITE_REGISTRATION(utils_thread_base_test);
+-
+-const int thread_test::test_flag_pre_stop;
+-const int thread_test::test_flag_long_timeout;
+-
+-const int thread_test::test_flag_acquire_global;
+-const int thread_test::test_flag_has_global;
+-
+-const int thread_test::test_flag_do_work;
+-const int thread_test::test_flag_pre_poke;
+-const int thread_test::test_flag_post_poke;
+-
+-void throw_shutdown_exception() { throw torrent::shutdown_exception(); }
+-
+-thread_test::thread_test() :
+-  m_test_state(TEST_NONE),
+-  m_test_flags(0) {
+-}
+-
+-void
+-thread_test::init_thread() {
+-  m_state = STATE_INITIALIZED;
+-  m_test_state = TEST_PRE_START;
+-  m_poll = torrent::PollSelect::create(256);
+-}
+-
+-void
+-thread_test::call_events() {
+-  if ((m_test_flags & test_flag_pre_stop) && m_test_state == TEST_PRE_START && m_state == STATE_ACTIVE)
+-    __sync_lock_test_and_set(&m_test_state, TEST_PRE_STOP);
+-
+-  if ((m_test_flags & test_flag_acquire_global)) {
+-    acquire_global_lock();
+-    __sync_and_and_fetch(&m_test_flags, ~test_flag_acquire_global);
+-    __sync_or_and_fetch(&m_test_flags, test_flag_has_global);
+-  }
+-
+-  if ((m_flags & flag_do_shutdown)) {
+-    if ((m_flags & flag_did_shutdown))
+-      throw torrent::internal_error("Already trigged shutdown.");
+-
+-    __sync_or_and_fetch(&m_flags, flag_did_shutdown);
+-    throw torrent::shutdown_exception();
+-  }
+-
+-  if ((m_test_flags & test_flag_pre_poke)) {
+-  }
+-
+-  if ((m_test_flags & test_flag_do_work)) {
+-    usleep(10 * 1000); // TODO: Don't just sleep, as that give up core.
+-    __sync_and_and_fetch(&m_test_flags, ~test_flag_do_work);
+-  }
+-
+-  if ((m_test_flags & test_flag_post_poke)) {
+-  }
+-}
+-
+-bool
+-wait_for_true(std::function<bool ()> test_function) {
+-  int i = 100;
+-
+-  do {
+-    if (test_function())
+-      return true;
+-
+-    usleep(10 * 1000);
+-  } while (--i);
+-
+-  return false;
+-}
+-
+-void
+-utils_thread_base_test::setUp() {
+-}
+-
+-void
+-utils_thread_base_test::tearDown() {
+-  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+-  torrent::thread_base::release_global_lock();
+-}
+-
+-void
+-utils_thread_base_test::test_basic() {
+-  thread_test* thread = new thread_test;
+-
+-  CPPUNIT_ASSERT(thread->flags() == 0);
+-
+-  CPPUNIT_ASSERT(!thread->is_main_polling());
+-  CPPUNIT_ASSERT(!thread->is_active());
+-  CPPUNIT_ASSERT(thread->global_queue_size() == 0);
+-  CPPUNIT_ASSERT(thread->poll() == NULL);
+-
+-  // Check active...
+-}
+-
+-void
+-utils_thread_base_test::test_lifecycle() {
+-  thread_test* thread = new thread_test;
+-
+-  CPPUNIT_ASSERT(thread->state() == torrent::thread_base::STATE_UNKNOWN);
+-  CPPUNIT_ASSERT(thread->test_state() == thread_test::TEST_NONE);
+-
+-  thread->init_thread();
+-  CPPUNIT_ASSERT(thread->state() == torrent::thread_base::STATE_INITIALIZED);
+-  CPPUNIT_ASSERT(thread->is_initialized());
+-  CPPUNIT_ASSERT(thread->test_state() == thread_test::TEST_PRE_START);
+-
+-  thread->set_pre_stop();
+-  CPPUNIT_ASSERT(!wait_for_true(std::bind(&thread_test::is_test_state, thread, thread_test::TEST_PRE_STOP)));
+-
+-  thread->start_thread();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_ACTIVE)));
+-  CPPUNIT_ASSERT(thread->is_active());
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_test_state, thread, thread_test::TEST_PRE_STOP)));
+-
+-  thread->stop_thread();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_INACTIVE)));
+-  CPPUNIT_ASSERT(thread->is_inactive());
+-
+-  delete thread;
+-}
+-
+-void
+-utils_thread_base_test::test_global_lock_basic() {
+-  thread_test* thread = new thread_test;
+-  
+-  thread->init_thread();
+-  thread->start_thread();
+-  
+-  CPPUNIT_ASSERT(torrent::thread_base::global_queue_size() == 0);
+-
+-  // Acquire main thread...
+-  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+-  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
+-
+-  torrent::thread_base::release_global_lock();
+-  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+-  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
+-    
+-  torrent::thread_base::release_global_lock();
+-  torrent::thread_base::acquire_global_lock();
+-  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
+-
+-  thread->set_acquire_global();
+-  CPPUNIT_ASSERT(!wait_for_true(std::bind(&thread_test::is_test_flags, thread, thread_test::test_flag_has_global)));
+-  
+-  torrent::thread_base::release_global_lock();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_test_flags, thread, thread_test::test_flag_has_global)));
+-
+-  CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
+-  torrent::thread_base::release_global_lock();
+-  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+-
+-  // Test waive (loop).
+-
+-  CPPUNIT_ASSERT(torrent::thread_base::global_queue_size() == 0);
+-
+-  torrent::thread_base::release_global_lock();
+-  thread->stop_thread();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_INACTIVE)));
+-
+-  delete thread;
+-}
+-
+-void
+-utils_thread_base_test::test_interrupt() {
+-  thread_test* thread = new thread_test;
+-  thread->set_test_flag(thread_test::test_flag_long_timeout);
+-
+-  thread->init_thread();
+-  thread->start_thread();
+-
+-  // Vary the various timeouts.
+-
+-  for (int i = 0; i < 100; i++) {
+-    thread->interrupt();
+-    usleep(0);
+-
+-    thread->set_test_flag(thread_test::test_flag_do_work);
+-    thread->interrupt();
+-
+-    // Wait for flag to clear.
+-    CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_not_test_flags, thread, thread_test::test_flag_do_work)));
+-  }
+-
+-  thread->stop_thread();
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&thread_test::is_state, thread, thread_test::STATE_INACTIVE)));
+-
+-  delete thread;
+-}
+-
+-void
+-utils_thread_base_test::test_stop() {
+-  CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock());
+-  // torrent::thread_base::acquire_global_lock();
+-
+-  for (int i = 0; i < 20; i++) {
+-    CPPUNIT_ASSERT(!torrent::thread_base::trylock_global_lock());
+-
+-    thread_test* thread = new thread_test;
+-    thread->set_test_flag(thread_test::test_flag_do_work);
+-
+-    thread->init_thread();
+-    thread->start_thread();
+-
+-    thread->stop_thread_wait();
+-    CPPUNIT_ASSERT(thread->is_inactive());
+-
+-    delete thread;
+-  }
+-
+-  torrent::thread_base::release_global_lock();
+-}
+diff --git a/test/torrent/utils/thread_base_test.h b/test/torrent/utils/thread_base_test.h
+deleted file mode 100644
+index 22eb99dc..00000000
+--- a/test/torrent/utils/thread_base_test.h
++++ /dev/null
+@@ -1,86 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "torrent/utils/thread_base.h"
+-
+-class utils_thread_base_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(utils_thread_base_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST(test_lifecycle);
+-
+-  CPPUNIT_TEST(test_global_lock_basic);
+-  CPPUNIT_TEST(test_interrupt);
+-  CPPUNIT_TEST(test_stop);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp();
+-  void tearDown();
+-
+-  void test_basic();
+-  void test_lifecycle();
+-
+-  void test_global_lock_basic();
+-  void test_interrupt();
+-  void test_interrupt_legacy();
+-  void test_stop();
+-};
+-
+-struct thread_management_type {
+-  thread_management_type() { CPPUNIT_ASSERT(torrent::thread_base::trylock_global_lock()); }
+-  ~thread_management_type() { torrent::thread_base::release_global_lock(); }
+-};
+-
+-#define SETUP_THREAD()                                                  \
+-  thread_management_type thread_management;                             \
+-  torrent::thread_disk* thread_disk = new torrent::thread_disk();       \
+-  thread_disk->init_thread();
+-
+-#define CLEANUP_THREAD()                                                \
+-  CPPUNIT_ASSERT(wait_for_true(std::bind(&torrent::thread_base::is_inactive, thread_disk))); \
+-  delete thread_disk;
+-
+-bool wait_for_true(std::function<bool ()> test_function);
+-
+-class thread_test : public torrent::thread_base {
+-public:
+-  enum test_state {
+-    TEST_NONE,
+-    TEST_PRE_START,
+-    TEST_PRE_STOP,
+-    TEST_STOP
+-  };
+-
+-  static const int test_flag_pre_stop       = 0x1;
+-  static const int test_flag_long_timeout   = 0x2;
+-
+-  static const int test_flag_acquire_global = 0x10;
+-  static const int test_flag_has_global     = 0x20;
+-
+-  static const int test_flag_do_work   = 0x100;
+-  static const int test_flag_pre_poke  = 0x200;
+-  static const int test_flag_post_poke = 0x400;
+-
+-  thread_test();
+-
+-  int                 test_state() const { return m_test_state; }
+-  bool                is_state(int state) const { return m_state == state; }
+-  bool                is_test_state(int state) const { return m_test_state == state; }
+-  bool                is_test_flags(int flags) const { return (m_test_flags & flags) == flags; }
+-  bool                is_not_test_flags(int flags) const { return !(m_test_flags & flags); }
+-
+-  const char*         name() const { return "test_thread"; }
+-
+-  void                init_thread();
+-
+-  void                set_pre_stop() { __sync_or_and_fetch(&m_test_flags, test_flag_pre_stop); }
+-  void                set_acquire_global() { __sync_or_and_fetch(&m_test_flags, test_flag_acquire_global); }
+-
+-  void                set_test_flag(int flags) { __sync_or_and_fetch(&m_test_flags, flags); }
+-
+-private:
+-  void                call_events();
+-  int64_t             next_timeout_usec() { return (m_test_flags & test_flag_long_timeout) ? (10000 * 1000) : (100 * 1000); }
+-
+-  int                 m_test_state lt_cacheline_aligned;
+-  int                 m_test_flags lt_cacheline_aligned;
+-};
+diff --git a/test/tracker/test_tracker_http.cc b/test/tracker/test_tracker_http.cc
+new file mode 100644
+index 00000000..399d00d5
+--- /dev/null
++++ b/test/tracker/test_tracker_http.cc
+@@ -0,0 +1,11 @@
++#include "config.h"
++
++#include "test_tracker_http.h"
++
++#include "tracker/tracker_http.h"
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_tracker_http, "tracker");
++
++void
++test_tracker_http::test_basic() {
++}
+diff --git a/test/tracker/test_tracker_http.h b/test/tracker/test_tracker_http.h
+new file mode 100644
+index 00000000..ab11a8f7
+--- /dev/null
++++ b/test/tracker/test_tracker_http.h
+@@ -0,0 +1,12 @@
++#include "helpers/test_fixture.h"
++
++#include "torrent/utils/thread_base.h"
++
++class test_tracker_http : public test_fixture {
++  CPPUNIT_TEST_SUITE(test_tracker_http);
++  CPPUNIT_TEST(test_basic);
++  CPPUNIT_TEST_SUITE_END();
++
++public:
++  void test_basic();
++};
+diff --git a/test/tracker/tracker_http_test.cc b/test/tracker/tracker_http_test.cc
+deleted file mode 100644
+index deda4382..00000000
+--- a/test/tracker/tracker_http_test.cc
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#include "config.h"
+-
+-#include "tracker_http_test.h"
+-
+-#include "tracker/tracker_http.h"
+-
+-void
+-tracker_http_test::setUp() {
+-}
+-
+-void
+-tracker_http_test::tearDown() {
+-}
+-
+-void
+-tracker_http_test::test_basic() {
+-}
+diff --git a/test/tracker/tracker_http_test.h b/test/tracker/tracker_http_test.h
+deleted file mode 100644
+index 11ff8246..00000000
+--- a/test/tracker/tracker_http_test.h
++++ /dev/null
+@@ -1,18 +0,0 @@
+-#include <cppunit/extensions/HelperMacros.h>
+-
+-#include "tracker/tracker_http.h"
+-
+-class tracker_http_test : public CppUnit::TestFixture {
+-  CPPUNIT_TEST_SUITE(tracker_http_test);
+-  CPPUNIT_TEST(test_basic);
+-  CPPUNIT_TEST(test_scrape);
+-  CPPUNIT_TEST_SUITE_END();
+-
+-public:
+-  void setUp();
+-  void tearDown();
+-
+-  void test_basic();
+-
+-  void test_scrape();
+-};
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0034-Changes-automake-required-files.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0034-Changes-automake-required-files.patch
new file mode 100644
index 000000000..e860045a7
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0034-Changes-automake-required-files.patch
@@ -0,0 +1,22 @@ 
+From 03e1c95987917bf98534e50fdd718a948540ffb2 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Thu, 25 Feb 2021 00:03:27 +0900
+Subject: [PATCH] Changes automake required files.
+
+---
+ autogen.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/autogen.sh b/autogen.sh
+index 79afab8e..6def96dd 100755
+--- a/autogen.sh
++++ b/autogen.sh
+@@ -36,7 +36,7 @@ echo automake...
+     exit 1
+ }
+ 
+-automake --add-missing --copy --gnu || exit 1
++automake --add-missing --copy --foreign || exit 1
+ 
+ echo autoconf...
+ (autoconf --version) < /dev/null > /dev/null 2>&1 || {
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0035-Replaced-custom-execinfo-autoconf-test.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0035-Replaced-custom-execinfo-autoconf-test.patch
new file mode 100644
index 000000000..0ff30731c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0035-Replaced-custom-execinfo-autoconf-test.patch
@@ -0,0 +1,48 @@ 
+From b4a3888bd891d804a83ae1cee623592725975895 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Sat, 27 Feb 2021 22:11:55 +0900
+Subject: [PATCH] Replaced custom execinfo autoconf test.
+
+---
+ configure.ac            |  2 +-
+ scripts/rak_execinfo.m4 | 11 -----------
+ 2 files changed, 1 insertion(+), 12 deletions(-)
+ delete mode 100644 scripts/rak_execinfo.m4
+
+diff --git a/configure.ac b/configure.ac
+index 88a46edd..197bbc94 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -34,7 +34,6 @@ RAK_CHECK_CXXFLAGS
+ RAK_ENABLE_DEBUG
+ RAK_ENABLE_EXTRA_DEBUG
+ RAK_ENABLE_WERROR
+-RAK_DISABLE_BACKTRACE
+ 
+ RAK_CHECK_CXX11
+ 
+@@ -58,6 +57,7 @@ TORRENT_WITH_INOTIFY
+ CC_ATTRIBUTE_VISIBILITY
+ 
+ AX_CHECK_ZLIB
++AX_EXECINFO
+ AX_PTHREAD
+ 
+ PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
+diff --git a/scripts/rak_execinfo.m4 b/scripts/rak_execinfo.m4
+deleted file mode 100644
+index c1d9b2f8..00000000
+--- a/scripts/rak_execinfo.m4
++++ /dev/null
+@@ -1,11 +0,0 @@
+-AC_DEFUN([RAK_DISABLE_BACKTRACE], [
+-  AC_ARG_ENABLE(backtrace,
+-    AC_HELP_STRING([--disable-backtrace], [disable backtrace information [[default=no]]]),
+-    [
+-        if test "$enableval" = "yes"; then
+-            AX_EXECINFO
+-        fi
+-    ],[
+-        AX_EXECINFO
+-    ])
+-])
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0036-Added-option-to-disable-pthread_setname_np.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0036-Added-option-to-disable-pthread_setname_np.patch
new file mode 100644
index 000000000..9d3c0fa23
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0036-Added-option-to-disable-pthread_setname_np.patch
@@ -0,0 +1,135 @@ 
+From e5ed6301e0d07adeaab10e9924a8c9a2e327cdc5 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Thu, 29 Apr 2021 19:33:04 +0900
+Subject: [PATCH] Added option to disable pthread_setname_np.
+
+---
+ configure.ac                     | 30 +++++++++++++++++++-----------
+ scripts/checks.m4                | 18 ++++++++++++++++++
+ src/torrent/utils/thread_base.cc | 16 ++++++++++++++--
+ 3 files changed, 51 insertions(+), 13 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 197bbc94..73caf712 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -24,9 +24,9 @@ AC_PROG_CXX
+ AC_SYS_LARGEFILE
+ 
+ AC_C_BIGENDIAN(
+-    AC_DEFINE(IS_BIG_ENDIAN, 1, Big endian),
+-    AC_DEFINE(IS_LITTLE_ENDIAN, 1, Little endian),
+-    AC_MSG_ERROR([Could not determine endianness])
++  AC_DEFINE(IS_BIG_ENDIAN, 1, Big endian),
++  AC_DEFINE(IS_LITTLE_ENDIAN, 1, Little endian),
++  AC_MSG_ERROR([Could not determine endianness])
+ )
+ 
+ RAK_CHECK_CFLAGS
+@@ -54,7 +54,15 @@ TORRENT_WITHOUT_STATVFS
+ TORRENT_WITHOUT_STATFS
+ TORRENT_WITH_INOTIFY
+ 
+-CC_ATTRIBUTE_VISIBILITY
++AC_ARG_ENABLE(attribute-visibility,
++  AC_HELP_STRING([--disable-attribute-visibility], [disable symbol visibility attribute [[default=enable]]]),
++  [
++    if test "$enableval" = "yes"; then
++      CC_ATTRIBUTE_VISIBILITY
++    fi
++  ],[
++    CC_ATTRIBUTE_VISIBILITY
++  ])
+ 
+ AX_CHECK_ZLIB
+ AX_EXECINFO
+@@ -71,11 +79,11 @@ TORRENT_ARG_CYRUS_RC4
+ 
+ AC_CHECK_FUNCS(posix_memalign)
+ 
+-TORRENT_CHECK_MADVISE()
+-TORRENT_CHECK_CACHELINE()
+-TORRENT_CHECK_POPCOUNT()
+-TORRENT_CHECK_PTHREAD_SETNAME_NP()
+-TORRENT_MINCORE()
++TORRENT_CHECK_MADVISE
++TORRENT_CHECK_CACHELINE
++TORRENT_CHECK_POPCOUNT
++TORRENT_DISABLE_PTHREAD_SETNAME_NP
++TORRENT_MINCORE
+ 
+ TORRENT_DISABLE_INSTRUMENTATION
+ 
+@@ -88,8 +96,8 @@ AC_SUBST(LIBTORRENT_CFLAGS)
+ AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included)
+ 
+ CC_ATTRIBUTE_UNUSED(
+-	AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
+-	AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
++  AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
++  AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
+ )
+ 
+ AC_OUTPUT([
+diff --git a/scripts/checks.m4 b/scripts/checks.m4
+index 98ef17f8..915a5011 100644
+--- a/scripts/checks.m4
++++ b/scripts/checks.m4
+@@ -490,3 +490,21 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
+     ])
+   ])
+ ])
++
++AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
++  AC_MSG_CHECKING([for pthread_setname_no])
++
++  AC_ARG_ENABLE(pthread-setname-np,
++    AC_HELP_STRING([--disable-pthread-setname-np], [disable pthread_setname_np]),
++    [
++      if test "$enableval" = "no"; then
++        AC_MSG_RESULT(disabled)
++      else
++        AC_MSG_RESULT(checking)
++        TORRENT_CHECK_PTHREAD_SETNAME_NP
++      fi
++    ], [
++      TORRENT_CHECK_PTHREAD_SETNAME_NP
++    ]
++  )
++])
+diff --git a/src/torrent/utils/thread_base.cc b/src/torrent/utils/thread_base.cc
+index 99d6355d..ec0619f3 100644
+--- a/src/torrent/utils/thread_base.cc
++++ b/src/torrent/utils/thread_base.cc
+@@ -41,10 +41,16 @@ thread_base::~thread_base() {
+ 
+ void
+ thread_base::start_thread() {
+-  if (m_poll == NULL)
++  if (this == nullptr)
++    throw internal_error("Called thread_base::start_thread on a nullptr.");
++
++  if (m_poll == nullptr)
+     throw internal_error("No poll object for thread defined.");
+ 
+-  if (!is_initialized() || pthread_create(&m_thread, NULL, (pthread_func)&thread_base::event_loop, this))
++  if (!is_initialized())
++    throw internal_error("Called thread_base::start_thread on an uninitialized object.");
++
++  if (pthread_create(&m_thread, NULL, (pthread_func)&thread_base::event_loop, this))
+     throw internal_error("Failed to create thread.");
+ }
+ 
+@@ -82,6 +88,12 @@ thread_base::should_handle_sigusr1() {
+ 
+ void*
+ thread_base::event_loop(thread_base* thread) {
++  if (thread == nullptr)
++    throw internal_error("thread_base::event_loop called with a null pointer thread");
++
++  if (!thread->is_initialized())
++    throw internal_error("thread_base::event_loop call on an uninitialized object");
++
+   __sync_lock_test_and_set(&thread->m_state, STATE_ACTIVE);
+ 
+ #if defined(HAS_PTHREAD_SETNAME_NP_DARWIN)
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0037-Improved-backtrace-error-checking.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0037-Improved-backtrace-error-checking.patch
new file mode 100644
index 000000000..5f48d76bf
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0037-Improved-backtrace-error-checking.patch
@@ -0,0 +1,594 @@ 
+From f978e68f9d907e25207d0a7d247d2b10935e5d76 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Thu, 29 Apr 2021 19:34:35 +0900
+Subject: [PATCH] Improved backtrace error checking.
+
+---
+ src/download/download_main.cc            | 36 -------------
+ src/download/download_main.h             | 36 -------------
+ src/download/download_wrapper.cc         | 43 ++--------------
+ src/torrent/data/download_data.h         | 36 -------------
+ src/torrent/download/choke_queue.cc      | 50 +++++-------------
+ src/torrent/download/resource_manager.cc | 53 +++++--------------
+ src/torrent/exceptions.cc                | 65 +++++++-----------------
+ src/torrent/torrent.cc                   |  1 +
+ src/torrent/utils/extents.h              | 36 -------------
+ src/torrent/utils/signal_bitfield.cc     | 36 -------------
+ 10 files changed, 48 insertions(+), 344 deletions(-)
+
+diff --git a/src/download/download_main.cc b/src/download/download_main.cc
+index 9a3f9df2..e075038a 100644
+--- a/src/download/download_main.cc
++++ b/src/download/download_main.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"
+ 
+ #include <cstring>
+diff --git a/src/download/download_main.h b/src/download/download_main.h
+index da3cf182..4783e863 100644
+--- a/src/download/download_main.h
++++ b/src/download/download_main.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_MAIN_H
+ #define LIBTORRENT_DOWNLOAD_MAIN_H
+ 
+diff --git a/src/download/download_wrapper.cc b/src/download/download_wrapper.cc
+index 59e81781..304bddce 100644
+--- a/src/download/download_wrapper.cc
++++ b/src/download/download_wrapper.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"
+ 
+ #include <iterator>
+@@ -62,6 +26,8 @@
+ 
+ #include "download_wrapper.h"
+ 
++#define LT_LOG_THIS(log_fmt, ...)                                       \
++  lt_log_print_info(LOG_TORRENT_INFO, this->info(), "download", log_fmt, __VA_ARGS__);
+ #define LT_LOG_STORAGE_ERRORS(log_fmt, ...)                             \
+   lt_log_print_info(LOG_PROTOCOL_STORAGE_ERRORS, this->info(), "storage_errors", log_fmt, __VA_ARGS__);
+ 
+@@ -325,8 +291,8 @@ DownloadWrapper::receive_tick(uint32_t ticks) {
+ 
+ void
+ DownloadWrapper::receive_update_priorities() {
+-  if (m_main->chunk_selector()->empty())
+-    return;
++  LT_LOG_THIS("update priorities: chunks_selected:%" PRIu32 " wanted_chunks:%" PRIu32,
++              m_main->chunk_selector()->size(), data()->wanted_chunks());
+ 
+   data()->mutable_high_priority()->clear();
+   data()->mutable_normal_priority()->clear();
+@@ -359,7 +325,6 @@ DownloadWrapper::receive_update_priorities() {
+   }
+ 
+   bool was_partial = data()->wanted_chunks() != 0;
+-
+   data()->update_wanted_chunks();
+ 
+   m_main->chunk_selector()->update_priorities();
+diff --git a/src/torrent/data/download_data.h b/src/torrent/data/download_data.h
+index fc212047..c701cb2f 100644
+--- a/src/torrent/data/download_data.h
++++ b/src/torrent/data/download_data.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_DATA_DOWNLOAD_DATA_H
+ #define LIBTORRENT_DATA_DOWNLOAD_DATA_H
+ 
+diff --git a/src/torrent/download/choke_queue.cc b/src/torrent/download/choke_queue.cc
+index 7c00b686..edf47795 100644
+--- a/src/torrent/download/choke_queue.cc
++++ b/src/torrent/download/choke_queue.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"
+ 
+ #include <algorithm>
+@@ -50,6 +14,10 @@
+ 
+ #include "choke_queue.h"
+ 
++// TODO: Add a different logging category.
++#define LT_LOG_THIS(log_fmt, ...)                                       \
++  lt_log_print_subsystem(LOG_TORRENT_INFO, "choke_queue", log_fmt, __VA_ARGS__);
++
+ namespace torrent {
+ 
+ struct choke_manager_less {
+@@ -193,6 +161,9 @@ choke_queue::rebuild_containers(container_type* queued, container_type* unchoked
+ 
+ void
+ choke_queue::balance() {
++  LT_LOG_THIS("balancing queue: heuristics:%i currently_unchoked:%" PRIu32 " max_unchoked:%" PRIu32,
++              m_heuristics, m_currently_unchoked, m_maxUnchoked)
++
+   // Return if no balancing is needed. Don't return if is_unlimited()
+   // as we might have just changed the value and have interested that
+   // can be unchoked.
+@@ -216,6 +187,9 @@ choke_queue::balance() {
+ 
+   // If we have more unchoked than max global slots allow for,
+   // 'can_unchoke' will be negative.
++  //
++  // Throws std::bad_function_call if 'set_slot_can_unchoke' is not
++  // set.
+   int can_unchoke = m_slotCanUnchoke();
+   int max_unchoked = std::min(m_maxUnchoked, (uint32_t)(1 << 20));
+ 
+@@ -240,8 +214,8 @@ choke_queue::balance() {
+   if (result != 0)
+     m_slotUnchoke(result);
+ 
+-  lt_log_print(LOG_PEER_DEBUG, "Called balance; adjust:%i can_unchoke:%i queued:%u unchoked:%u result:%i.",
+-               adjust, can_unchoke, (unsigned)queued.size(), (unsigned)unchoked.size(), result);
++  LT_LOG_THIS("balanced queue: adjust:%i can_unchoke:%i queued:%" PRIu32 " unchoked:%" PRIu32 " result:%i",
++               adjust, can_unchoke, queued.size(), unchoked.size(), result);
+ }
+ 
+ void
+diff --git a/src/torrent/download/resource_manager.cc b/src/torrent/download/resource_manager.cc
+index 51434c91..8ca7b02e 100644
+--- a/src/torrent/download/resource_manager.cc
++++ b/src/torrent/download/resource_manager.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"
+ 
+ #include <algorithm>
+@@ -51,6 +15,11 @@
+ #include "choke_queue.h"
+ #include "resource_manager.h"
+ 
++#define LT_LOG_THIS(log_fmt, ...)                                       \
++  lt_log_print_subsystem(LOG_TORRENT_INFO, "resource_manager", log_fmt, __VA_ARGS__);
++#define LT_LOG_ITR(log_fmt, ...)                                        \
++  lt_log_print_info(LOG_TORRENT_INFO, itr->download()->info(), "resource_manager", log_fmt, __VA_ARGS__);
++
+ namespace torrent {
+ 
+ const Rate* resource_manager_entry::up_rate() const { return m_download->info()->up_rate(); }
+@@ -226,6 +195,8 @@ ResourceManager::group_index_of(const std::string& name) {
+ 
+ void
+ ResourceManager::set_priority(iterator itr, uint16_t pri) {
++  LT_LOG_ITR("set priority: %" PRIu16, 0)
++
+   itr->set_priority(pri);
+ }
+ 
+@@ -283,7 +254,7 @@ ResourceManager::set_max_download_unchoked(unsigned int m) {
+ // possibly multiple calls of this function.
+ void
+ ResourceManager::receive_upload_unchoke(int num) {
+-  lt_log_print(LOG_PEER_INFO, "Upload unchoked slots adjust; currently:%u adjust:%i", m_currentlyUploadUnchoked, num);
++  LT_LOG_THIS("adjusting upload unchoked slots; current:%u adjusted:%i", m_currentlyUploadUnchoked, num);
+ 
+   if ((int)m_currentlyUploadUnchoked + num < 0)
+     throw internal_error("ResourceManager::receive_upload_unchoke(...) received an invalid value.");
+@@ -293,7 +264,7 @@ ResourceManager::receive_upload_unchoke(int num) {
+ 
+ void
+ ResourceManager::receive_download_unchoke(int num) {
+-  lt_log_print(LOG_PEER_INFO, "Download unchoked slots adjust; currently:%u adjust:%i", m_currentlyDownloadUnchoked, num);
++  LT_LOG_THIS("adjusting download unchoked slots; current:%u adjusted:%i", m_currentlyDownloadUnchoked, num);
+ 
+   if ((int)m_currentlyDownloadUnchoked + num < 0)
+     throw internal_error("ResourceManager::receive_download_unchoke(...) received an invalid value.");
+@@ -387,12 +358,14 @@ ResourceManager::balance_unchoked(unsigned int weight, unsigned int max_unchoked
+     std::sort(group_first, group_last, std::bind(std::less<uint32_t>(),
+                                                  std::bind(&choke_group::up_requested, std::placeholders::_1),
+                                                  std::bind(&choke_group::up_requested, std::placeholders::_2)));
+-    lt_log_print(LOG_PEER_DEBUG, "Upload unchoked slots cycle; currently:%u adjusted:%i max_unchoked:%u", m_currentlyUploadUnchoked, change, max_unchoked);
++
++    LT_LOG_THIS("balancing upload unchoked slots; current_unchoked:%u change:%i max_unchoked:%u", m_currentlyUploadUnchoked, change, max_unchoked);
+   } else {
+     std::sort(group_first, group_last, std::bind(std::less<uint32_t>(),
+                                                  std::bind(&choke_group::down_requested, std::placeholders::_1),
+                                                  std::bind(&choke_group::down_requested, std::placeholders::_2)));
+-    lt_log_print(LOG_PEER_DEBUG, "Download unchoked slots cycle; currently:%u adjusted:%i max_unchoked:%u", m_currentlyDownloadUnchoked, change, max_unchoked);
++
++    LT_LOG_THIS("balancing download unchoked slots; current_unchoked:%u change:%i max_unchoked:%u", m_currentlyDownloadUnchoked, change, max_unchoked);
+   }
+ 
+   while (group_first != group_last) {
+diff --git a/src/torrent/exceptions.cc b/src/torrent/exceptions.cc
+index f834f9fa..7375ed8e 100644
+--- a/src/torrent/exceptions.cc
++++ b/src/torrent/exceptions.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"
+ 
+ #include <cerrno>
+@@ -73,23 +37,30 @@ void
+ internal_error::initialize(const std::string& msg) {
+   m_msg = msg;
+ 
+-  std::stringstream output;
+-
+ #ifdef HAVE_BACKTRACE
+-  void* stackPtrs[20];
++  void* stack_ptrs[20];
++  int stack_size = ::backtrace(stack_ptrs, 20);
++  char** stack_symbol_names = ::backtrace_symbols(stack_ptrs, stack_size);
+ 
+-  // Print the stack and exit.
+-  int stackSize = ::backtrace(stackPtrs, 20);
+-  char** stackStrings = backtrace_symbols(stackPtrs, stackSize);
++  if (stack_symbol_names == nullptr) {
++    m_backtrace = "backtrace_symbols failed";
++    return;
++  }
+ 
+-  for (int i = 0; i < stackSize; ++i)
+-    output << stackStrings[i] << std::endl;
++  std::stringstream output;
+ 
+-#else
+-  output << "Stack dump not enabled." << std::endl;
+-#endif
++  for (int i = 0; i < stack_size; ++i) {
++    if (stack_symbol_names[i] != nullptr && stack_symbol_names[i] > (void*)0x1000)
++      output << stack_symbol_names[i] << std::endl;
++    else
++      output << "stack_symbol: nullptr" << std::endl;
++  }
+ 
+   m_backtrace = output.str();
++
++#else
++  m_backtrace = "stack dump not enabled";
++#endif
+ }
+ 
+ }
+diff --git a/src/torrent/torrent.cc b/src/torrent/torrent.cc
+index fb70d247..67de4387 100644
+--- a/src/torrent/torrent.cc
++++ b/src/torrent/torrent.cc
+@@ -203,6 +203,7 @@ download_priority(Download d) {
+   return itr->priority();
+ }
+ 
++// TODO: Remove this.
+ void
+ download_set_priority(Download d, uint32_t pri) {
+   ResourceManager::iterator itr = manager->resource_manager()->find(d.ptr()->main());
+diff --git a/src/torrent/utils/extents.h b/src/torrent/utils/extents.h
+index c2b887b1..64605d4a 100644
+--- a/src/torrent/utils/extents.h
++++ b/src/torrent/utils/extents.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_UTILS_EXTENTS_H
+ #define LIBTORRENT_UTILS_EXTENTS_H
+ 
+diff --git a/src/torrent/utils/signal_bitfield.cc b/src/torrent/utils/signal_bitfield.cc
+index 82f81e7c..dfc3d1fe 100644
+--- a/src/torrent/utils/signal_bitfield.cc
++++ b/src/torrent/utils/signal_bitfield.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"
+ 
+ #include "torrent/exceptions.h"
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0038-Fixed-issue-with-multiple-connections-from-NAT-not-w.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0038-Fixed-issue-with-multiple-connections-from-NAT-not-w.patch
new file mode 100644
index 000000000..8937e869f
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0038-Fixed-issue-with-multiple-connections-from-NAT-not-w.patch
@@ -0,0 +1,199 @@ 
+From cabc557fdf6f12fee7029081de2cf5de88464c21 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Thu, 29 Apr 2021 21:27:50 +0900
+Subject: [PATCH] Fixed issue with multiple connections from NAT not working.
+
+---
+ src/protocol/handshake.cc     | 36 -------------------
+ src/torrent/peer/peer_list.cc | 68 +++++++++++------------------------
+ src/torrent/peer/peer_list.h  | 36 -------------------
+ 3 files changed, 20 insertions(+), 120 deletions(-)
+
+diff --git a/src/protocol/handshake.cc b/src/protocol/handshake.cc
+index 1b877c7a..d6f48e59 100644
+--- a/src/protocol/handshake.cc
++++ b/src/protocol/handshake.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"
+ 
+ #include <stdio.h>
+diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc
+index 080a7f13..6ce630f7 100644
+--- a/src/torrent/peer/peer_list.cc
++++ b/src/torrent/peer/peer_list.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"
+ 
+ #include <algorithm>
+@@ -262,8 +226,11 @@ PeerList::available_list_size() const {
+   return m_available_list->size();
+ }
+ 
++// TODO: Rename connecting:
+ PeerInfo*
+ PeerList::connected(const sockaddr* sa, int flags) {
++  // TODO: Rewrite to use new socket address api after fixing bug.
++
+   const rak::socket_address* address = rak::socket_address::cast_from(sa);
+   socket_address_key sock_key = socket_address_key::from_sockaddr(sa);
+ 
+@@ -281,13 +248,7 @@ PeerList::connected(const sockaddr* sa, int flags) {
+   // We should also remove any PeerInfo objects already for this
+   // address.
+   if ((filter_value & PeerInfo::flag_unwanted)) {
+-    char ipv4_str[INET_ADDRSTRLEN];
+-    uint32_t net_order_addr = htonl(host_byte_order_ipv4_addr);
+-
+-    inet_ntop(AF_INET, &net_order_addr, ipv4_str, INET_ADDRSTRLEN);
+-
+-    lt_log_print(LOG_PEER_INFO, "Peer %s is unwanted: preventing connection", ipv4_str);
+-
++    LT_LOG_EVENTS("connecting peer rejected, flagged as unwanted: " LT_LOG_SA_FMT, address->address_str().c_str(), address->port());
+     return NULL;
+   }
+ 
+@@ -313,12 +274,23 @@ PeerList::connected(const sockaddr* sa, int flags) {
+     //
+     // This also ensure we can connect to peers running on the same
+     // host as the tracker.
+-    if (flags & connect_keep_handshakes &&
+-        range.first->second->is_handshake() &&
+-        rak::socket_address::cast_from(range.first->second->socket_address())->port() != address->port())
+-      m_available_list->buffer()->push_back(*address);
++    // if (flags & connect_keep_handshakes &&
++    //     range.first->second->is_handshake() &&
++    //     rak::socket_address::cast_from(range.first->second->socket_address())->port() != address->port())
++    //   m_available_list->buffer()->push_back(*address);
+ 
+-    return NULL;
++    LT_LOG_EVENTS("connecting peer rejected, already connected (buggy, fixme): " LT_LOG_SA_FMT, address->address_str().c_str(), address->port());
++
++    // TODO: Verify this works properly, possibly add a check/flag
++    // that allows the handshake manager to notify peer list if the
++    // incoming connection was a duplicate peer hash.
++
++    //return NULL;
++
++    peerInfo = new PeerInfo(sa);
++    peerInfo->set_flags(filter_value & PeerInfo::mask_ip_table);
++
++    base_type::insert(range.second, value_type(sock_key, peerInfo));
+   }
+ 
+   if (flags & connect_filter_recent &&
+diff --git a/src/torrent/peer/peer_list.h b/src/torrent/peer/peer_list.h
+index 4c2f707d..a9d31a54 100644
+--- a/src/torrent/peer/peer_list.h
++++ b/src/torrent/peer/peer_list.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_PEER_LIST_H
+ #define LIBTORRENT_PEER_LIST_H
+ 
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0039-Added-disable-execinfo-option-to-configure.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0039-Added-disable-execinfo-option-to-configure.patch
new file mode 100644
index 000000000..a631b8de9
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0039-Added-disable-execinfo-option-to-configure.patch
@@ -0,0 +1,32 @@ 
+From 532d3e54b3f012dc81530ebb80ded8b26434fdd9 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Wed, 16 Jun 2021 23:28:28 +0900
+Subject: [PATCH] Added '--disable-execinfo' option to configure.
+
+---
+ configure.ac | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 73caf712..a4f051e4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -64,8 +64,17 @@ AC_ARG_ENABLE(attribute-visibility,
+     CC_ATTRIBUTE_VISIBILITY
+   ])
+ 
++AC_ARG_ENABLE(execinfo,
++  AC_HELP_STRING([--disable-execinfo], [disable libexecinfo [[default=enable]]]),
++  [
++    if test "$enableval" = "yes"; then
++      AX_EXECINFO
++    fi
++  ],[
++    AX_EXECINFO
++  ])
++
+ AX_CHECK_ZLIB
+-AX_EXECINFO
+ AX_PTHREAD
+ 
+ PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0040-Detect-ip-address.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0040-Detect-ip-address.patch
new file mode 100644
index 000000000..196d2f6af
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0040-Detect-ip-address.patch
@@ -0,0 +1,457 @@ 
+From 92781533fc4afab67447e8e6d47a649383179c44 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Sun, 20 Jun 2021 18:10:52 +0900
+Subject: [PATCH] Detect ip address.
+
+---
+ src/net/local_addr.cc                   |   6 +-
+ src/torrent/Makefile.am                 |   5 +-
+ src/torrent/net/fd.cc                   |   3 +
+ src/torrent/net/fd.h                    |  14 ++--
+ src/torrent/net/socket_address.cc       |   2 +-
+ src/torrent/net/socket_address.h        |   2 +-
+ src/torrent/net/utils.cc                | 104 ++++++++++++++++++++++++
+ src/torrent/net/utils.h                 |   9 ++
+ src/tracker/tracker_http.cc             | 104 ++++++++----------------
+ test/helpers/network.h                  |   2 +
+ test/torrent/net/test_fd.cc             |   9 ++
+ test/torrent/net/test_socket_address.cc |   2 +-
+ 12 files changed, 181 insertions(+), 81 deletions(-)
+ create mode 100755 src/torrent/net/utils.cc
+ create mode 100755 src/torrent/net/utils.h
+
+diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc
+index 24413265..0c7116cb 100644
+--- a/src/net/local_addr.cc
++++ b/src/net/local_addr.cc
+@@ -34,6 +34,8 @@
+ //           Skomakerveien 33
+ //           3185 Skoppum, NORWAY
+ 
++// TODO: Remove.
++
+ #include "config.h"
+ 
+ #include <stdio.h>
+@@ -241,7 +243,7 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) {
+       int plen = IFA_PAYLOAD(nlmsg);
+       for (const rtattr *rta = IFA_RTA(ifa);
+            RTA_OK(rta, plen);
+-	   rta = RTA_NEXT(rta, plen)) {
++           rta = RTA_NEXT(rta, plen)) {
+         if (rta->rta_type != IFA_LOCAL &&
+             rta->rta_type != IFA_ADDRESS) {
+           continue;
+@@ -303,7 +305,7 @@ get_local_address(sa_family_t family, rak::socket_address *address) {
+     dummy_dest.set_address_c_str("4.0.0.0"); 
+     break;
+   case rak::socket_address::af_inet6:
+-    dummy_dest.set_address_c_str("2001:700::"); 
++    dummy_dest.set_address_c_str("2001:1::");
+     break;
+   default:
+     throw internal_error("Unknown address family");
+diff --git a/src/torrent/Makefile.am b/src/torrent/Makefile.am
+index 30157b95..5de7e8ae 100644
+--- a/src/torrent/Makefile.am
++++ b/src/torrent/Makefile.am
+@@ -46,6 +46,8 @@ libtorrent_torrent_la_SOURCES = \
+ 	net/socket_event.cc \
+ 	net/socket_event.h \
+ 	net/types.h \
++	net/utils.cc \
++	net/utils.h \
+ \
+ 	peer/choke_status.h \
+ 	peer/client_info.cc \
+@@ -167,7 +169,8 @@ libtorrent_torrent_net_include_HEADERS = \
+ 	net/socket_address.h \
+ 	net/socket_address_key.h \
+ 	net/socket_event.h \
+-	net/types.h
++	net/types.h \
++	net/utils.h
+ 
+ libtorrent_torrent_peer_includedir = $(includedir)/torrent/peer
+ libtorrent_torrent_peer_include_HEADERS = \
+diff --git a/src/torrent/net/fd.cc b/src/torrent/net/fd.cc
+index 07c91779..6d228181 100644
+--- a/src/torrent/net/fd.cc
++++ b/src/torrent/net/fd.cc
+@@ -64,6 +64,9 @@ fd_open(fd_flags flags) {
+   if ((flags & fd_flag_stream)) {
+     domain = SOCK_STREAM;
+     protocol = IPPROTO_TCP;
++  } else if ((flags & fd_flag_datagram)) {
++    domain = SOCK_DGRAM;
++    protocol = IPPROTO_UDP;
+   } else {
+     LT_LOG_FLAG("fd_open missing socket type");
+     errno = EINVAL;
+diff --git a/src/torrent/net/fd.h b/src/torrent/net/fd.h
+index a7094646..6ab3302d 100644
+--- a/src/torrent/net/fd.h
++++ b/src/torrent/net/fd.h
+@@ -9,11 +9,12 @@ namespace torrent {
+ 
+ enum fd_flags : int {
+   fd_flag_stream = 0x1,
+-  fd_flag_nonblock = 0x10,
+-  fd_flag_reuse_address = 0x20,
+-  fd_flag_v4only = 0x40,
+-  fd_flag_v6only = 0x80,
+-  fd_flag_all = 0xff,
++  fd_flag_datagram = 0x10,
++  fd_flag_nonblock = 0x20,
++  fd_flag_reuse_address = 0x40,
++  fd_flag_v4only = 0x80,
++  fd_flag_v6only = 0x100,
++  fd_flag_all = 0x1ff,
+ };
+ 
+ constexpr bool fd_valid_flags(fd_flags flags);
+@@ -53,7 +54,8 @@ operator |=(fd_flags& lhs, fd_flags rhs) {
+ constexpr bool
+ fd_valid_flags(fd_flags flags) {
+   return
+-    (flags & fd_flag_stream) &&
++    ((flags & fd_flag_stream) || (flags & fd_flag_datagram)) &&
++    !((flags & fd_flag_stream) && (flags & fd_flag_datagram)) &&
+     !((flags & fd_flag_v4only) && (flags & fd_flag_v6only)) &&
+     !(flags & ~(fd_flag_all));
+ }
+diff --git a/src/torrent/net/socket_address.cc b/src/torrent/net/socket_address.cc
+index c36ba0ae..078bee25 100644
+--- a/src/torrent/net/socket_address.cc
++++ b/src/torrent/net/socket_address.cc
+@@ -135,7 +135,7 @@ sa_unique_ptr
+ sa_make_unspec() {
+   sa_unique_ptr sa(new sockaddr);
+ 
+-  std::memset(sa.get(), 0, sizeof(sa));
++  std::memset(sa.get(), 0, sizeof(sockaddr));
+   sa.get()->sa_family = AF_UNSPEC;
+ 
+   return sa;
+diff --git a/src/torrent/net/socket_address.h b/src/torrent/net/socket_address.h
+index f64aee68..b9586ca1 100644
+--- a/src/torrent/net/socket_address.h
++++ b/src/torrent/net/socket_address.h
+@@ -102,8 +102,8 @@ bool fd_sap_equal(const fd_sap_tuple& lhs, const fd_sap_tuple& rhs) LIBTORRENT_E
+ 
+ inline bool sap_is_unspec(const sa_unique_ptr& sap) { return sa_is_unspec(sap.get()); }
+ inline bool sap_is_unspec(const c_sa_unique_ptr& sap) { return sa_is_unspec(sap.get()); }
+-inline bool sap_is_inet(const c_sa_unique_ptr& sap) { return sa_is_inet(sap.get()); }
+ inline bool sap_is_inet(const sa_unique_ptr& sap) { return sa_is_inet(sap.get()); }
++inline bool sap_is_inet(const c_sa_unique_ptr& sap) { return sa_is_inet(sap.get()); }
+ inline bool sap_is_inet6(const sa_unique_ptr& sap) { return sa_is_inet6(sap.get()); }
+ inline bool sap_is_inet6(const c_sa_unique_ptr& sap) { return sa_is_inet6(sap.get()); }
+ inline bool sap_is_inet_inet6(const sa_unique_ptr& sap) { return sa_is_inet_inet6(sap.get()); }
+diff --git a/src/torrent/net/utils.cc b/src/torrent/net/utils.cc
+new file mode 100755
+index 00000000..4cb85924
+--- /dev/null
++++ b/src/torrent/net/utils.cc
+@@ -0,0 +1,104 @@
++#import <torrent/net/utils.h>
++
++#import <cerrno>
++#import <cstring>
++#import <torrent/net/fd.h>
++#import <torrent/net/socket_address.h>
++#import <torrent/utils/log.h>
++
++#define LT_LOG_ERROR(log_fmt)                                           \
++  lt_log_print(LOG_CONNECTION_FD, "fd: " log_fmt " (errno:%i message:'%s')", \
++               errno, std::strerror(errno));
++#define LT_LOG_FD(log_fmt)                                              \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt, fd);
++#define LT_LOG_FD_ERROR(log_fmt)                                        \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (errno:%i message:'%s')", \
++               fd, errno, std::strerror(errno));
++#define LT_LOG_FD_SIN(log_fmt)                                        \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (address:%s)", \
++               fd, sin_pretty_str(sa.get()).c_str());
++#define LT_LOG_FD_SIN6(log_fmt)                                       \
++  lt_log_print(LOG_CONNECTION_FD, "fd->%i: " log_fmt " (address:%s)", \
++               fd, sin6_pretty_str(sa.get()).c_str());
++
++namespace torrent {
++
++auto detect_local_sin_addr() -> sin_unique_ptr {
++  int fd = fd_open(fd_flag_v4only | fd_flag_datagram);
++  if (fd == -1) {
++    LT_LOG_ERROR("detect_local_sin_addr: open failed");
++    return sin_unique_ptr();
++  }
++
++  // TODO: Check if unique_ptr works.
++  std::shared_ptr<void> _fd(nullptr, [fd](...){ fd_close(fd); });
++
++  auto connectAddress = sin_make();
++  connectAddress.get()->sin_addr.s_addr = htonl(0x04000001);
++  connectAddress.get()->sin_port = 80;
++
++  if (!fd_connect(fd, reinterpret_cast<sockaddr*>(connectAddress.get())) && errno != EINPROGRESS) {
++    LT_LOG_FD_ERROR("detect_local_sin_addr: connect failed");
++    return sin_unique_ptr();
++  }
++
++  // TODO: Make sa function.
++  socklen_t socklen = sizeof(sockaddr_in);
++
++  auto sa = sin_make();
++
++  if (::getsockname(fd, reinterpret_cast<sockaddr*>(sa.get()), &socklen) != 0) {
++    LT_LOG_FD_ERROR("detect_local_sin_addr: getsockname failed");
++    return sin_unique_ptr();
++  }
++  if (socklen != sizeof(sockaddr_in)) {
++    LT_LOG_FD("detect_local_sin_addr: getsockname failed, invalid socklen");
++    return sin_unique_ptr();
++  }
++
++  LT_LOG_FD_SIN("detect_local_sin_addr: success");
++
++  return sa;
++}
++
++auto detect_local_sin6_addr() -> sin6_unique_ptr {
++  int fd = fd_open(fd_flag_v6only | fd_flag_datagram);
++  if (fd == -1) {
++    LT_LOG_ERROR("detect_local_sin6_addr: open failed");
++    return sin6_unique_ptr();
++  }
++
++  // TODO: Check if unique_ptr works.
++  std::shared_ptr<void> _fd(nullptr, [fd](...){ fd_close(fd); });
++
++  auto connectAddress = sin6_make();
++  connectAddress.get()->sin6_addr.s6_addr[0] = 0x20;
++  connectAddress.get()->sin6_addr.s6_addr[1] = 0x01;
++  connectAddress.get()->sin6_addr.s6_addr[15] = 0x01;
++  connectAddress.get()->sin6_port = 80;
++
++  if (!fd_connect(fd, reinterpret_cast<sockaddr*>(connectAddress.get())) && errno != EINPROGRESS) {
++    LT_LOG_FD_ERROR("detect_local_sin6_addr: connect failed");
++    return sin6_unique_ptr();
++  }
++
++  // TODO: Make sa function.
++  socklen_t socklen = sizeof(sockaddr_in6);
++
++  auto sa = sin6_make();
++
++  if (::getsockname(fd, reinterpret_cast<sockaddr*>(sa.get()), &socklen) != 0) {
++    LT_LOG_FD_ERROR("detect_local_sin6_addr: getsockname failed");
++    return sin6_unique_ptr();
++  }
++  if (socklen != sizeof(sockaddr_in6)) {
++    LT_LOG_FD("detect_local_sin6_addr: getsockname failed, invalid socklen");
++    return sin6_unique_ptr();
++  }
++
++  LT_LOG_FD_SIN6("detect_local_sin6_addr: success");
++
++  return sa;
++}
++
++}
+diff --git a/src/torrent/net/utils.h b/src/torrent/net/utils.h
+new file mode 100755
+index 00000000..1d550c51
+--- /dev/null
++++ b/src/torrent/net/utils.h
+@@ -0,0 +1,9 @@
++#import <torrent/common.h>
++#import <torrent/net/socket_address.h>
++
++namespace torrent {
++
++auto detect_local_sin_addr() -> sin_unique_ptr;
++auto detect_local_sin6_addr() -> sin6_unique_ptr;
++
++}
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index 1bf94107..de3a39ab 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -1,63 +1,29 @@
+-// 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"
+ 
+ #define __STDC_FORMAT_MACROS
+ 
+-#include <iomanip>
+-#include <sstream>
+-#include <rak/functional.h>
+-#include <rak/string_manip.h>
+-
+-#include "net/address_list.h"
+-#include "net/local_addr.h"
+-#include "torrent/connection_manager.h"
+-#include "torrent/download_info.h"
+-#include "torrent/exceptions.h"
+-#include "torrent/http.h"
+-#include "torrent/object_stream.h"
+-#include "torrent/tracker_list.h"
+-#include "torrent/utils/log.h"
+-#include "torrent/utils/option_strings.h"
+-
+-#include "tracker_http.h"
+-
+-#include "globals.h"
+-#include "manager.h"
++#import <iomanip>
++#import <sstream>
++#import <rak/functional.h>
++#import <rak/string_manip.h>
++
++#import "net/address_list.h"
++#import "net/local_addr.h"
++#import "torrent/connection_manager.h"
++#import "torrent/download_info.h"
++#import "torrent/exceptions.h"
++#import "torrent/http.h"
++#import "torrent/net/utils.h"
++#import "torrent/net/socket_address.h"
++#import "torrent/object_stream.h"
++#import "torrent/tracker_list.h"
++#import "torrent/utils/log.h"
++#import "torrent/utils/option_strings.h"
++
++#import "tracker_http.h"
++
++#import "globals.h"
++#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__);
+@@ -142,19 +108,19 @@ TrackerHttp::send_state(int state) {
+ 
+   const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
+ 
+-  if (!localAddress->is_address_any())
+-    s << "&ip=" << localAddress->address_str();
+-  
+-  if (localAddress->is_address_any() && localAddress->family() == rak::socket_address::pf_inet) {
+-    rak::socket_address local_v6;
+-    if (get_local_address(rak::socket_address::af_inet6, &local_v6))
+-      s << "&ipv6=" << rak::copy_escape_html(local_v6.address_str());
+-  }
++  if (localAddress->is_address_any()) {
++    auto ipv4_address = detect_local_sin_addr();
++    auto ipv6_address = detect_local_sin6_addr();
+ 
+-  if (localAddress->is_address_any() && localAddress->family() == rak::socket_address::pf_inet6) {
+-    rak::socket_address local_v4;
+-    if (get_local_address(rak::socket_address::af_inet, &local_v4))
+-      s << "&ipv4=" << local_v4.address_str();
++    if (ipv4_address != nullptr) {
++      s << "&ipv4=" << sin_addr_str(ipv4_address.get());
++    }
++    if (ipv6_address != nullptr) {
++      s << "&ipv6=" << sin6_addr_str(ipv6_address.get());
++    }
++
++  } else {
++    s << "&ip=" << localAddress->address_str();
+   }
+ 
+   if (info->is_compact())
+diff --git a/test/helpers/network.h b/test/helpers/network.h
+index 6cf2f870..eb188426 100644
+--- a/test/helpers/network.h
++++ b/test/helpers/network.h
+@@ -112,6 +112,7 @@ wrap_ai_get_first_sa(const char* nodename, const char* servname = nullptr, const
+ 
+   CPPUNIT_ASSERT_MESSAGE(("wrap_ai_get_first_sa: nodename:'" + std::string(nodename) + "'").c_str(),
+                         sa != nullptr);
++
+   return sa;
+ }
+ 
+@@ -121,6 +122,7 @@ wrap_ai_get_first_c_sa(const char* nodename, const char* servname = nullptr, con
+ 
+   CPPUNIT_ASSERT_MESSAGE(("wrap_ai_get_first_sa: nodename:'" + std::string(nodename) + "'").c_str(),
+                         sa != nullptr);
++
+   return torrent::c_sa_unique_ptr(sa.release());
+ }
+ 
+diff --git a/test/torrent/net/test_fd.cc b/test/torrent/net/test_fd.cc
+index 5e56f0f3..0a00ccd4 100644
+--- a/test/torrent/net/test_fd.cc
++++ b/test/torrent/net/test_fd.cc
+@@ -9,13 +9,22 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test_fd, "torrent/net");
+ void
+ test_fd::test_valid_flags() {
+   CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_datagram));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_datagram));
++
+   CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_nonblock));
+   CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_reuse_address));
+   CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only));
+   CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v6only));
+ 
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_datagram | torrent::fd_flag_nonblock));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_datagram | torrent::fd_flag_reuse_address));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_datagram | torrent::fd_flag_v4only));
++  CPPUNIT_ASSERT(torrent::fd_valid_flags(torrent::fd_flag_datagram | torrent::fd_flag_v6only));
++
+   CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_v4only | torrent::fd_flag_v6only));
+   CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_stream | torrent::fd_flag_v4only | torrent::fd_flag_v6only));
++  CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flag_datagram | torrent::fd_flag_v4only | torrent::fd_flag_v6only));
+ 
+   CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags()));
+   CPPUNIT_ASSERT(!torrent::fd_valid_flags(torrent::fd_flags(~torrent::fd_flag_all)));
+diff --git a/test/torrent/net/test_socket_address.cc b/test/torrent/net/test_socket_address.cc
+index 8a1b0c8a..a27b38bc 100644
+--- a/test/torrent/net/test_socket_address.cc
++++ b/test/torrent/net/test_socket_address.cc
+@@ -83,7 +83,7 @@ test_socket_address::test_make() {
+   CPPUNIT_ASSERT(sin6_inet6->sin6_family == AF_INET6);
+   CPPUNIT_ASSERT(sin6_inet6->sin6_port == 0);
+   CPPUNIT_ASSERT(sin6_inet6->sin6_flowinfo == 0);
+-  CPPUNIT_ASSERT(compare_sin6_addr(sin6_inet6->sin6_addr, in6_addr{0}));
++  CPPUNIT_ASSERT(compare_sin6_addr(sin6_inet6->sin6_addr, (in6_addr{0})));
+   CPPUNIT_ASSERT(sin6_inet6->sin6_scope_id == 0);
+ 
+   torrent::sa_unique_ptr sa_unix = torrent::sa_make_unix("");
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0041-Added-ipv6-options.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0041-Added-ipv6-options.patch
new file mode 100644
index 000000000..923f5c97c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0041-Added-ipv6-options.patch
@@ -0,0 +1,85 @@ 
+From e646ed5427b690b75208510d328457af66b208e8 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Mon, 21 Jun 2021 21:12:56 +0900
+Subject: [PATCH] Added ipv6 options.
+
+---
+ src/torrent/connection_manager.cc |  6 +++++-
+ src/torrent/connection_manager.h  | 13 +++++++++++++
+ src/tracker/tracker_http.cc       | 13 +++++--------
+ 3 files changed, 23 insertions(+), 9 deletions(-)
+
+diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc
+index 972dcbfc..ea5efc58 100644
+--- a/src/torrent/connection_manager.cc
++++ b/src/torrent/connection_manager.cc
+@@ -89,7 +89,11 @@ ConnectionManager::ConnectionManager() :
+ 
+   m_listen(new Listen),
+   m_listen_port(0),
+-  m_listen_backlog(SOMAXCONN) {
++  m_listen_backlog(SOMAXCONN),
++
++  m_block_ipv4(false),
++  m_block_ipv6(false),
++  m_prefer_ipv6(false) {
+ 
+   m_bindAddress = (new rak::socket_address())->c_sockaddr();
+   m_localAddress = (new rak::socket_address())->c_sockaddr();
+diff --git a/src/torrent/connection_manager.h b/src/torrent/connection_manager.h
+index cf43b0bf..09ccdd28 100644
+--- a/src/torrent/connection_manager.h
++++ b/src/torrent/connection_manager.h
+@@ -167,6 +167,15 @@ public:
+   // For internal usage.
+   Listen*             listen()            { return m_listen; }
+ 
++  bool                is_block_ipv4() const  { return m_block_ipv4; }
++  void                set_block_ipv4(bool v) { m_block_ipv4 = v; }
++
++  bool                is_block_ipv6() const  { return m_block_ipv6; }
++  void                set_block_ipv6(bool v) { m_block_ipv6 = v; }
++
++  bool                is_prefer_ipv6() const  { return m_prefer_ipv6; }
++  void                set_prefer_ipv6(bool v) { m_prefer_ipv6 = v; }
++
+ private:
+   ConnectionManager(const ConnectionManager&);
+   void operator = (const ConnectionManager&);
+@@ -190,6 +199,10 @@ private:
+   slot_filter_type    m_slot_filter;
+   slot_resolver_type  m_slot_resolver;
+   slot_throttle_type  m_slot_address_throttle;
++
++  bool                m_block_ipv4;
++  bool                m_block_ipv6;
++  bool                m_prefer_ipv6;
+ };
+ 
+ }
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index de3a39ab..fdbbd58a 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -109,16 +109,13 @@ TrackerHttp::send_state(int state) {
+   const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
+ 
+   if (localAddress->is_address_any()) {
+-    auto ipv4_address = detect_local_sin_addr();
+-    auto ipv6_address = detect_local_sin6_addr();
++    if (manager->connection_manager()->is_prefer_ipv6()) {
++      auto ipv6_address = detect_local_sin6_addr();
+ 
+-    if (ipv4_address != nullptr) {
+-      s << "&ipv4=" << sin_addr_str(ipv4_address.get());
++      if (ipv6_address != nullptr) {
++        s << "&ip=" << sin6_addr_str(ipv6_address.get());
++      }
+     }
+-    if (ipv6_address != nullptr) {
+-      s << "&ipv6=" << sin6_addr_str(ipv6_address.get());
+-    }
+-
+   } else {
+     s << "&ip=" << localAddress->address_str();
+   }
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0042-Removed-obsolete-files.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0042-Removed-obsolete-files.patch
new file mode 100644
index 000000000..383984179
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0042-Removed-obsolete-files.patch
@@ -0,0 +1,444 @@ 
+From 54caef85baca975e0be30b4f3f6de01db19c8e19 Mon Sep 17 00:00:00 2001
+From: rakshasa <sundell.software@gmail.com>
+Date: Mon, 21 Jun 2021 21:28:02 +0900
+Subject: [PATCH] Removed obsolete files.
+
+---
+ src/Makefile.am             |   2 -
+ src/net/local_addr.cc       | 329 ------------------------------------
+ src/net/local_addr.h        |  64 -------
+ src/tracker/tracker_http.cc |   1 -
+ 4 files changed, 396 deletions(-)
+ delete mode 100644 src/net/local_addr.cc
+ delete mode 100644 src/net/local_addr.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 95e6a7ae..925e7e15 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -76,8 +76,6 @@ libtorrent_other_la_SOURCES = \
+ 	net/address_list.cc \
+ 	net/address_list.h \
+ 	net/data_buffer.h \
+-	net/local_addr.cc \
+-	net/local_addr.h \
+ 	net/listen.cc \
+ 	net/listen.h \
+ 	net/protocol_buffer.h \
+diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc
+deleted file mode 100644
+index 0c7116cb..00000000
+--- a/src/net/local_addr.cc
++++ /dev/null
+@@ -1,329 +0,0 @@
+-// libTorrent - BitTorrent library
+-// Copyright (C) 2005-2007, 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
+-
+-// TODO: Remove.
+-
+-#include "config.h"
+-
+-#include <stdio.h>
+-#include <rak/socket_address.h>
+-#include <sys/types.h>
+-#include <errno.h>
+-
+-#ifdef __linux__
+-#include <linux/netlink.h>
+-#include <linux/rtnetlink.h>
+-#endif
+-
+-#include "torrent/exceptions.h"
+-#include "socket_fd.h"
+-#include "local_addr.h"
+-
+-namespace torrent {
+-
+-#ifdef __linux__
+-
+-namespace {
+-
+-// IPv4 priority, from highest to lowest:
+-//
+-//   1. Everything else (global address)
+-//   2. Private address space (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
+-//   3. Empty/INADDR_ANY (0.0.0.0)
+-//   4. Link-local address (169.254.0.0/16)
+-//   5. Localhost (127.0.0.0/8)
+-int
+-get_priority_ipv4(const in_addr& addr) {
+-  if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x7f000000U)) {
+-    return 5;
+-  }
+-  if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) {
+-    return 4;
+-  }
+-  if (addr.s_addr == htonl(0)) {
+-    return 3;
+-  }
+-  if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x0a000000U) ||
+-      (addr.s_addr & htonl(0xfff00000U)) == htonl(0xac100000U) ||
+-      (addr.s_addr & htonl(0xffff0000U)) == htonl(0xc0a80000U)) {
+-    return 2;
+-  }
+-  return 1;
+-}
+-
+-// IPv6 priority, from highest to lowest:
+-//
+-//  1. Global address (2000::/16 not in 6to4 or Teredo)
+-//  2. 6to4 (2002::/16)
+-//  3. Teredo (2001::/32)
+-//  4. Empty/INADDR_ANY (::)
+-//  5. Everything else (link-local, ULA, etc.)
+-int
+-get_priority_ipv6(const in6_addr& addr) {
+-  const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(addr.s6_addr);
+-  if (addr32[0] == htonl(0) &&
+-      addr32[1] == htonl(0) &&
+-      addr32[2] == htonl(0) &&
+-      addr32[3] == htonl(0)) {
+-    return 4;
+-  }
+-  if (addr32[0] == htonl(0x20010000)) {
+-    return 3;
+-  }
+-  if ((addr32[0] & htonl(0xffff0000)) == htonl(0x20020000)) {
+-    return 2;
+-  }
+-  if ((addr32[0] & htonl(0xe0000000)) == htonl(0x20000000)) {
+-    return 1;
+-  }
+-  return 5;
+-}
+-
+-int
+-get_priority(const rak::socket_address& addr) {
+-  switch (addr.family()) {
+-  case AF_INET:
+-    return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr);
+-  case AF_INET6:
+-    return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr);
+-  default:
+-    throw torrent::internal_error("Unknown address family given to compare");
+-  }
+-}
+-
+-}
+-
+-// Linux-specific implementation that understands how to filter away
+-// understands how to filter away secondary addresses.
+-bool get_local_address(sa_family_t family, rak::socket_address *address) {
+-  rak::socket_address best_addr;
+-  switch (family) {
+-  case AF_INET:
+-    best_addr.sa_inet()->clear();
+-    break;
+-  case AF_INET6:
+-    best_addr.sa_inet6()->clear();
+-    break;
+-  default:
+-    throw torrent::internal_error("Unknown address family given to get_local_address");
+-  }
+-
+-  // The bottom bit of the priority is used to hold if the address is 
+-  // a secondary address (e.g. with IPv6 privacy extensions) or not;
+-  // secondary addresses have lower priority (higher number).
+-  int best_addr_pri = get_priority(best_addr) * 2;
+-
+-  // Get all the addresses via Linux' netlink interface.
+-  int fd = ::socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+-  if (fd == -1) {
+-    return false;
+-  }
+-
+-  struct sockaddr_nl nladdr;
+-  memset(&nladdr, 0, sizeof(nladdr));
+-  nladdr.nl_family = AF_NETLINK;
+-  if (::bind(fd, (sockaddr *)&nladdr, sizeof(nladdr))) {
+-    ::close(fd);
+-    return false;
+-  }
+-
+-  const int seq_no = 1;
+-  struct {
+-    nlmsghdr nh;
+-    rtgenmsg g;
+-  } req;
+-  memset(&req, 0, sizeof(req));
+-
+-  req.nh.nlmsg_len = sizeof(req);
+-  req.nh.nlmsg_type = RTM_GETADDR;
+-  req.nh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+-  req.nh.nlmsg_pid = getpid();
+-  req.nh.nlmsg_seq = seq_no;
+-  req.g.rtgen_family = AF_UNSPEC;
+-
+-  int ret;
+-  do {
+-    ret = ::sendto(fd, &req, sizeof(req), 0, (sockaddr *)&nladdr, sizeof(nladdr));
+-  } while (ret == -1 && errno == EINTR);
+-
+-  if (ret == -1) {
+-    ::close(fd);
+-    return false;
+-  }
+-
+-  bool done = false;
+-  do {
+-    char buf[4096];
+-    socklen_t len = sizeof(nladdr);
+-    do {
+-      ret = ::recvfrom(fd, buf, sizeof(buf), 0, (sockaddr *)&nladdr, &len);
+-    } while (ret == -1 && errno == EINTR);
+-
+-    if (ret < 0) {
+-      ::close(fd);
+-      return false;
+-    }
+-
+-    for (const nlmsghdr *nlmsg = (const nlmsghdr *)buf;
+-         NLMSG_OK(nlmsg, ret);
+-         nlmsg = NLMSG_NEXT(nlmsg, ret)) {
+-      if (nlmsg->nlmsg_seq != seq_no)
+-        continue;
+-      if (nlmsg->nlmsg_type == NLMSG_DONE) {
+-        done = true;
+-        break;
+-      }
+-      if (nlmsg->nlmsg_type == NLMSG_ERROR) {
+-        ::close(fd);
+-        return false;
+-      }
+-      if (nlmsg->nlmsg_type != RTM_NEWADDR)
+-        continue;
+-
+-      const ifaddrmsg *ifa = (const ifaddrmsg *)NLMSG_DATA(nlmsg);
+-
+-      if (ifa->ifa_family != family)
+-        continue; 
+-
+-#ifdef IFA_F_OPTIMISTIC
+-      if ((ifa->ifa_flags & IFA_F_OPTIMISTIC) != 0)
+-        continue;
+-#endif
+-#ifdef IFA_F_DADFAILED
+-      if ((ifa->ifa_flags & IFA_F_DADFAILED) != 0)
+-        continue;
+-#endif
+-#ifdef IFA_F_DEPRECATED
+-      if ((ifa->ifa_flags & IFA_F_DEPRECATED) != 0)
+-        continue;
+-#endif
+-#ifdef IFA_F_TENTATIVE
+-      if ((ifa->ifa_flags & IFA_F_TENTATIVE) != 0)
+-        continue;
+-#endif
+-  
+-      // Since there can be point-to-point links on the machine, we need to keep
+-      // track of the addresses we've seen for this interface; if we see both
+-      // IFA_LOCAL and IFA_ADDRESS for an interface, keep only the IFA_LOCAL.
+-      rak::socket_address this_addr;
+-      bool seen_addr = false;
+-      int plen = IFA_PAYLOAD(nlmsg);
+-      for (const rtattr *rta = IFA_RTA(ifa);
+-           RTA_OK(rta, plen);
+-           rta = RTA_NEXT(rta, plen)) {
+-        if (rta->rta_type != IFA_LOCAL &&
+-            rta->rta_type != IFA_ADDRESS) {
+-          continue;
+-        }
+-        if (rta->rta_type == IFA_ADDRESS && seen_addr) {
+-          continue;
+-        }
+-        seen_addr = true;
+-        switch (ifa->ifa_family) {
+-        case AF_INET:
+-          this_addr.sa_inet()->clear();
+-          this_addr.sa_inet()->set_address(*(const in_addr *)RTA_DATA(rta));
+-          break;
+-        case AF_INET6:
+-          this_addr.sa_inet6()->clear();
+-          this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta));
+-          break;
+-        }
+-      }
+-      if (!seen_addr)
+-        continue;
+-       
+-      int this_addr_pri = get_priority(this_addr) * 2;
+-      if ((ifa->ifa_flags & IFA_F_SECONDARY) == IFA_F_SECONDARY) {
+-        ++this_addr_pri;
+-      }
+-
+-      if (this_addr_pri < best_addr_pri) {
+-        best_addr = this_addr;
+-        best_addr_pri = this_addr_pri;
+-      }
+-    }
+-  } while (!done);
+-
+-  ::close(fd);
+-  if (!best_addr.is_address_any()) {
+-    *address = best_addr;
+-    return true;
+-  } else {
+-    return false;
+-  } 
+-}
+-
+-#else
+-
+-// Generic POSIX variant.
+-bool
+-get_local_address(sa_family_t family, rak::socket_address *address) {
+-  SocketFd sock;
+-  if (!sock.open_datagram()) {
+-    return false;
+-  }
+-
+-  rak::socket_address dummy_dest;
+-  dummy_dest.clear();
+-
+-  switch (family) {
+-  case rak::socket_address::af_inet:
+-    dummy_dest.set_address_c_str("4.0.0.0"); 
+-    break;
+-  case rak::socket_address::af_inet6:
+-    dummy_dest.set_address_c_str("2001:1::");
+-    break;
+-  default:
+-    throw internal_error("Unknown address family");
+-  }
+-
+-  dummy_dest.set_port(80);
+-
+-  if (!sock.connect(dummy_dest)) {
+-    sock.close();
+-    return false;
+-  }
+-
+-  bool ret = sock.getsockname(address);
+-  sock.close();
+-
+-  return ret;
+-}
+-
+-#endif
+-
+-}
+diff --git a/src/net/local_addr.h b/src/net/local_addr.h
+deleted file mode 100644
+index 43bc8206..00000000
+--- a/src/net/local_addr.h
++++ /dev/null
+@@ -1,64 +0,0 @@
+-// libTorrent - BitTorrent library
+-// Copyright (C) 2005-2007, 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
+-
+-// A routine to get a local IP address that can be presented to a tracker.
+-// (Does not use UPnP etc., so will not understand NAT.)
+-// On a machine with multiple network cards, address selection can be a
+-// complex process, and in general what's selected is a source/destination
+-// address pair. However, this routine will give an approximation that will
+-// be good enough for most purposes and users.
+-
+-#ifndef LIBTORRENT_NET_LOCAL_ADDR_H
+-#define LIBTORRENT_NET_LOCAL_ADDR_H
+-
+-#include <unistd.h>
+-
+-namespace rak {
+-  class socket_address;
+-}
+-
+-namespace torrent {
+-
+-// Note: family must currently be rak::af_inet or rak::af_inet6
+-// (rak::af_unspec won't do); anything else will throw an exception.
+-// Returns false if no address of the given family could be found,
+-// either because there are none, or because something went wrong in
+-// the process (e.g., no free file descriptors).
+-bool get_local_address(sa_family_t family, rak::socket_address *address);
+-
+-}
+-
+-#endif /* LIBTORRENT_NET_LOCAL_ADDR_H */
+diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
+index fdbbd58a..22c409a1 100644
+--- a/src/tracker/tracker_http.cc
++++ b/src/tracker/tracker_http.cc
+@@ -8,7 +8,6 @@
+ #import <rak/string_manip.h>
+ 
+ #import "net/address_list.h"
+-#import "net/local_addr.h"
+ #import "torrent/connection_manager.h"
+ #import "torrent/download_info.h"
+ #import "torrent/exceptions.h"
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0043-Updated-and-cleaned-up-automake.-224.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0043-Updated-and-cleaned-up-automake.-224.patch
new file mode 100644
index 000000000..965f61a4e
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0043-Updated-and-cleaned-up-automake.-224.patch
@@ -0,0 +1,2979 @@ 
+From 4cfe9b1dc1349ad167969d6cf87f557600f34a2e Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Sat, 7 Aug 2021 17:49:35 +0900
+Subject: [PATCH] Updated and cleaned up automake. (#224)
+
+---
+ INSTALL                             | 371 +++++++----
+ autogen.sh                          |  51 --
+ configure.ac                        |  32 +-
+ scripts/ax_check_zlib.m4            |  11 +-
+ scripts/ax_cxx_compile_stdcxx.m4    | 962 ++++++++++++++++++++++++++++
+ scripts/ax_cxx_compile_stdcxx_0x.m4 | 106 ---
+ scripts/ax_cxx_compile_stdcxx_11.m4 | 147 -----
+ scripts/ax_pthread.m4               | 453 +++++++++----
+ scripts/checks.m4                   | 104 ++-
+ scripts/common.m4                   |  29 +-
+ scripts/rak_compiler.m4             |   6 +-
+ scripts/rak_cxx.m4                  |  14 -
+ 12 files changed, 1642 insertions(+), 644 deletions(-)
+ delete mode 100755 autogen.sh
+ mode change 100644 => 100755 scripts/ax_check_zlib.m4
+ create mode 100755 scripts/ax_cxx_compile_stdcxx.m4
+ delete mode 100644 scripts/ax_cxx_compile_stdcxx_0x.m4
+ delete mode 100644 scripts/ax_cxx_compile_stdcxx_11.m4
+ mode change 100644 => 100755 scripts/ax_pthread.m4
+ delete mode 100644 scripts/rak_cxx.m4
+
+diff --git a/INSTALL b/INSTALL
+index 54caf7c1..8865734f 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -1,81 +1,109 @@
+-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
++Installation Instructions
++*************************
++
++   Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
+ Foundation, Inc.
+ 
+-   This file is free documentation; the Free Software Foundation gives
+-unlimited permission to copy, distribute and modify it.
++   Copying and distribution of this file, with or without modification,
++are permitted in any medium without royalty provided the copyright
++notice and this notice are preserved.  This file is offered as-is,
++without warranty of any kind.
+ 
+ Basic Installation
+ ==================
+ 
+-   These are generic installation instructions.
++   Briefly, the shell command './configure && make && make install'
++should configure, build, and install this package.  The following
++more-detailed instructions are generic; see the 'README' file for
++instructions specific to this package.  Some packages provide this
++'INSTALL' file but do not implement all of the features documented
++below.  The lack of an optional feature in a given package is not
++necessarily a bug.  More recommendations for GNU packages can be found
++in *note Makefile Conventions: (standards)Makefile Conventions.
+ 
+-   The `configure' shell script attempts to guess correct values for
++   The 'configure' shell script attempts to guess correct values for
+ various system-dependent variables used during compilation.  It uses
+-those values to create a `Makefile' in each directory of the package.
+-It may also create one or more `.h' files containing system-dependent
+-definitions.  Finally, it creates a shell script `config.status' that
++those values to create a 'Makefile' in each directory of the package.
++It may also create one or more '.h' files containing system-dependent
++definitions.  Finally, it creates a shell script 'config.status' that
+ you can run in the future to recreate the current configuration, and a
+-file `config.log' containing compiler output (useful mainly for
+-debugging `configure').
++file 'config.log' containing compiler output (useful mainly for
++debugging 'configure').
+ 
+-   It can also use an optional file (typically called `config.cache'
+-and enabled with `--cache-file=config.cache' or simply `-C') that saves
+-the results of its tests to speed up reconfiguring.  (Caching is
+-disabled by default to prevent problems with accidental use of stale
+-cache files.)
++   It can also use an optional file (typically called 'config.cache' and
++enabled with '--cache-file=config.cache' or simply '-C') that saves the
++results of its tests to speed up reconfiguring.  Caching is disabled by
++default to prevent problems with accidental use of stale cache files.
+ 
+    If you need to do unusual things to compile the package, please try
+-to figure out how `configure' could check whether to do them, and mail
+-diffs or instructions to the address given in the `README' so they can
++to figure out how 'configure' could check whether to do them, and mail
++diffs or instructions to the address given in the 'README' so they can
+ be considered for the next release.  If you are using the cache, and at
+-some point `config.cache' contains results you don't want to keep, you
++some point 'config.cache' contains results you don't want to keep, you
+ may remove or edit it.
+ 
+-   The file `configure.ac' (or `configure.in') is used to create
+-`configure' by a program called `autoconf'.  You only need
+-`configure.ac' if you want to change it or regenerate `configure' using
+-a newer version of `autoconf'.
++   The file 'configure.ac' (or 'configure.in') is used to create
++'configure' by a program called 'autoconf'.  You need 'configure.ac' if
++you want to change it or regenerate 'configure' using a newer version of
++'autoconf'.
++
++   The simplest way to compile this package is:
+ 
+-The simplest way to compile this package is:
++  1. 'cd' to the directory containing the package's source code and type
++     './configure' to configure the package for your system.
+ 
+-  1. `cd' to the directory containing the package's source code and type
+-     `./configure' to configure the package for your system.  If you're
+-     using `csh' on an old version of System V, you might need to type
+-     `sh ./configure' instead to prevent `csh' from trying to execute
+-     `configure' itself.
++     Running 'configure' might take a while.  While running, it prints
++     some messages telling which features it is checking for.
+ 
+-     Running `configure' takes awhile.  While running, it prints some
+-     messages telling which features it is checking for.
++  2. Type 'make' to compile the package.
+ 
+-  2. Type `make' to compile the package.
++  3. Optionally, type 'make check' to run any self-tests that come with
++     the package, generally using the just-built uninstalled binaries.
+ 
+-  3. Optionally, type `make check' to run any self-tests that come with
+-     the package.
++  4. Type 'make install' to install the programs and any data files and
++     documentation.  When installing into a prefix owned by root, it is
++     recommended that the package be configured and built as a regular
++     user, and only the 'make install' phase executed with root
++     privileges.
+ 
+-  4. Type `make install' to install the programs and any data files and
+-     documentation.
++  5. Optionally, type 'make installcheck' to repeat any self-tests, but
++     this time using the binaries in their final installed location.
++     This target does not install anything.  Running this target as a
++     regular user, particularly if the prior 'make install' required
++     root privileges, verifies that the installation completed
++     correctly.
+ 
+-  5. You can remove the program binaries and object files from the
+-     source code directory by typing `make clean'.  To also remove the
+-     files that `configure' created (so you can compile the package for
+-     a different kind of computer), type `make distclean'.  There is
+-     also a `make maintainer-clean' target, but that is intended mainly
++  6. You can remove the program binaries and object files from the
++     source code directory by typing 'make clean'.  To also remove the
++     files that 'configure' created (so you can compile the package for
++     a different kind of computer), type 'make distclean'.  There is
++     also a 'make maintainer-clean' target, but that is intended mainly
+      for the package's developers.  If you use it, you may have to get
+      all sorts of other programs in order to regenerate files that came
+      with the distribution.
+ 
++  7. Often, you can also type 'make uninstall' to remove the installed
++     files again.  In practice, not all packages have tested that
++     uninstallation works correctly, even though it is required by the
++     GNU Coding Standards.
++
++  8. Some packages, particularly those that use Automake, provide 'make
++     distcheck', which can by used by developers to test that all other
++     targets like 'make install' and 'make uninstall' work correctly.
++     This target is generally not run by end users.
++
+ Compilers and Options
+ =====================
+ 
+    Some systems require unusual options for compilation or linking that
+-the `configure' script does not know about.  Run `./configure --help'
++the 'configure' script does not know about.  Run './configure --help'
+ for details on some of the pertinent environment variables.
+ 
+-   You can give `configure' initial values for configuration parameters
+-by setting variables in the command line or in the environment.  Here
+-is an example:
++   You can give 'configure' initial values for configuration parameters
++by setting variables in the command line or in the environment.  Here is
++an example:
+ 
+-     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
++     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+ 
+    *Note Defining Variables::, for more details.
+ 
+@@ -84,146 +112,257 @@ Compiling For Multiple Architectures
+ 
+    You can compile the package for more than one kind of computer at the
+ same time, by placing the object files for each architecture in their
+-own directory.  To do this, you must use a version of `make' that
+-supports the `VPATH' variable, such as GNU `make'.  `cd' to the
++own directory.  To do this, you can use GNU 'make'.  'cd' to the
+ directory where you want the object files and executables to go and run
+-the `configure' script.  `configure' automatically checks for the
+-source code in the directory that `configure' is in and in `..'.
++the 'configure' script.  'configure' automatically checks for the source
++code in the directory that 'configure' is in and in '..'.  This is known
++as a "VPATH" build.
++
++   With a non-GNU 'make', it is safer to compile the package for one
++architecture at a time in the source code directory.  After you have
++installed the package for one architecture, use 'make distclean' before
++reconfiguring for another architecture.
++
++   On MacOS X 10.5 and later systems, you can create libraries and
++executables that work on multiple system types--known as "fat" or
++"universal" binaries--by specifying multiple '-arch' options to the
++compiler but only a single '-arch' option to the preprocessor.  Like
++this:
++
++     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
++                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
++                 CPP="gcc -E" CXXCPP="g++ -E"
+ 
+-   If you have to use a `make' that does not support the `VPATH'
+-variable, you have to compile the package for one architecture at a
+-time in the source code directory.  After you have installed the
+-package for one architecture, use `make distclean' before reconfiguring
+-for another architecture.
++   This is not guaranteed to produce working output in all cases, you
++may have to build one architecture at a time and combine the results
++using the 'lipo' tool if you have problems.
+ 
+ Installation Names
+ ==================
+ 
+-   By default, `make install' will install the package's files in
+-`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+-installation prefix other than `/usr/local' by giving `configure' the
+-option `--prefix=PATH'.
++   By default, 'make install' installs the package's commands under
++'/usr/local/bin', include files under '/usr/local/include', etc.  You
++can specify an installation prefix other than '/usr/local' by giving
++'configure' the option '--prefix=PREFIX', where PREFIX must be an
++absolute file name.
+ 
+    You can specify separate installation prefixes for
+ architecture-specific files and architecture-independent files.  If you
+-give `configure' the option `--exec-prefix=PATH', the package will use
+-PATH as the prefix for installing programs and libraries.
+-Documentation and other data files will still use the regular prefix.
++pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
++PREFIX as the prefix for installing programs and libraries.
++Documentation and other data files still use the regular prefix.
+ 
+    In addition, if you use an unusual directory layout you can give
+-options like `--bindir=PATH' to specify different values for particular
+-kinds of files.  Run `configure --help' for a list of the directories
+-you can set and what kinds of files go in them.
+-
+-   If the package supports it, you can cause programs to be installed
+-with an extra prefix or suffix on their names by giving `configure' the
+-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
++options like '--bindir=DIR' to specify different values for particular
++kinds of files.  Run 'configure --help' for a list of the directories
++you can set and what kinds of files go in them.  In general, the default
++for these options is expressed in terms of '${prefix}', so that
++specifying just '--prefix' will affect all of the other directory
++specifications that were not explicitly provided.
++
++   The most portable way to affect installation locations is to pass the
++correct locations to 'configure'; however, many packages provide one or
++both of the following shortcuts of passing variable assignments to the
++'make install' command line to change installation locations without
++having to reconfigure or recompile.
++
++   The first method involves providing an override variable for each
++affected directory.  For example, 'make install
++prefix=/alternate/directory' will choose an alternate location for all
++directory configuration variables that were expressed in terms of
++'${prefix}'.  Any directories that were specified during 'configure',
++but not in terms of '${prefix}', must each be overridden at install time
++for the entire installation to be relocated.  The approach of makefile
++variable overrides for each directory variable is required by the GNU
++Coding Standards, and ideally causes no recompilation.  However, some
++platforms have known limitations with the semantics of shared libraries
++that end up requiring recompilation when using this method, particularly
++noticeable in packages that use GNU Libtool.
++
++   The second method involves providing the 'DESTDIR' variable.  For
++example, 'make install DESTDIR=/alternate/directory' will prepend
++'/alternate/directory' before all installation names.  The approach of
++'DESTDIR' overrides is not required by the GNU Coding Standards, and
++does not work on platforms that have drive letters.  On the other hand,
++it does better at avoiding recompilation issues, and works well even
++when some directory options were not specified in terms of '${prefix}'
++at 'configure' time.
+ 
+ Optional Features
+ =================
+ 
+-   Some packages pay attention to `--enable-FEATURE' options to
+-`configure', where FEATURE indicates an optional part of the package.
+-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+-is something like `gnu-as' or `x' (for the X Window System).  The
+-`README' should mention any `--enable-' and `--with-' options that the
++   If the package supports it, you can cause programs to be installed
++with an extra prefix or suffix on their names by giving 'configure' the
++option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
++
++   Some packages pay attention to '--enable-FEATURE' options to
++'configure', where FEATURE indicates an optional part of the package.
++They may also pay attention to '--with-PACKAGE' options, where PACKAGE
++is something like 'gnu-as' or 'x' (for the X Window System).  The
++'README' should mention any '--enable-' and '--with-' options that the
+ package recognizes.
+ 
+-   For packages that use the X Window System, `configure' can usually
++   For packages that use the X Window System, 'configure' can usually
+ find the X include and library files automatically, but if it doesn't,
+-you can use the `configure' options `--x-includes=DIR' and
+-`--x-libraries=DIR' to specify their locations.
++you can use the 'configure' options '--x-includes=DIR' and
++'--x-libraries=DIR' to specify their locations.
++
++   Some packages offer the ability to configure how verbose the
++execution of 'make' will be.  For these packages, running './configure
++--enable-silent-rules' sets the default to minimal output, which can be
++overridden with 'make V=1'; while running './configure
++--disable-silent-rules' sets the default to verbose, which can be
++overridden with 'make V=0'.
++
++Particular systems
++==================
++
++   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU CC
++is not installed, it is recommended to use the following options in
++order to use an ANSI C compiler:
++
++     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
++
++and if that doesn't work, install pre-built binaries of GCC for HP-UX.
++
++   HP-UX 'make' updates targets which have the same time stamps as their
++prerequisites, which makes it generally unusable when shipped generated
++files such as 'configure' are involved.  Use GNU 'make' instead.
++
++   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
++parse its '<wchar.h>' header file.  The option '-nodtk' can be used as a
++workaround.  If GNU CC is not installed, it is therefore recommended to
++try
++
++     ./configure CC="cc"
++
++and if that doesn't work, try
++
++     ./configure CC="cc -nodtk"
++
++   On Solaris, don't put '/usr/ucb' early in your 'PATH'.  This
++directory contains several dysfunctional programs; working variants of
++these programs are available in '/usr/bin'.  So, if you need '/usr/ucb'
++in your 'PATH', put it _after_ '/usr/bin'.
++
++   On Haiku, software installed for all users goes in '/boot/common',
++not '/usr/local'.  It is recommended to use the following options:
++
++     ./configure --prefix=/boot/common
+ 
+ Specifying the System Type
+ ==========================
+ 
+-   There may be some features `configure' cannot figure out
++   There may be some features 'configure' cannot figure out
+ automatically, but needs to determine by the type of machine the package
+ will run on.  Usually, assuming the package is built to be run on the
+-_same_ architectures, `configure' can figure that out, but if it prints
++_same_ architectures, 'configure' can figure that out, but if it prints
+ a message saying it cannot guess the machine type, give it the
+-`--build=TYPE' option.  TYPE can either be a short name for the system
+-type, such as `sun4', or a canonical name which has the form:
++'--build=TYPE' option.  TYPE can either be a short name for the system
++type, such as 'sun4', or a canonical name which has the form:
+ 
+      CPU-COMPANY-SYSTEM
+ 
+ where SYSTEM can have one of these forms:
+ 
+-     OS KERNEL-OS
++     OS
++     KERNEL-OS
+ 
+-   See the file `config.sub' for the possible values of each field.  If
+-`config.sub' isn't included in this package, then this package doesn't
++   See the file 'config.sub' for the possible values of each field.  If
++'config.sub' isn't included in this package, then this package doesn't
+ need to know the machine type.
+ 
+    If you are _building_ compiler tools for cross-compiling, you should
+-use the `--target=TYPE' option to select the type of system they will
++use the option '--target=TYPE' to select the type of system they will
+ produce code for.
+ 
+    If you want to _use_ a cross compiler, that generates code for a
+ platform different from the build platform, you should specify the
+ "host" platform (i.e., that on which the generated programs will
+-eventually be run) with `--host=TYPE'.
++eventually be run) with '--host=TYPE'.
+ 
+ Sharing Defaults
+ ================
+ 
+-   If you want to set default values for `configure' scripts to share,
+-you can create a site shell script called `config.site' that gives
+-default values for variables like `CC', `cache_file', and `prefix'.
+-`configure' looks for `PREFIX/share/config.site' if it exists, then
+-`PREFIX/etc/config.site' if it exists.  Or, you can set the
+-`CONFIG_SITE' environment variable to the location of the site script.
+-A warning: not all `configure' scripts look for a site script.
++   If you want to set default values for 'configure' scripts to share,
++you can create a site shell script called 'config.site' that gives
++default values for variables like 'CC', 'cache_file', and 'prefix'.
++'configure' looks for 'PREFIX/share/config.site' if it exists, then
++'PREFIX/etc/config.site' if it exists.  Or, you can set the
++'CONFIG_SITE' environment variable to the location of the site script.
++A warning: not all 'configure' scripts look for a site script.
+ 
+ Defining Variables
+ ==================
+ 
+    Variables not defined in a site shell script can be set in the
+-environment passed to `configure'.  However, some packages may run
++environment passed to 'configure'.  However, some packages may run
+ configure again during the build, and the customized values of these
+ variables may be lost.  In order to avoid this problem, you should set
+-them in the `configure' command line, using `VAR=value'.  For example:
++them in the 'configure' command line, using 'VAR=value'.  For example:
+ 
+      ./configure CC=/usr/local2/bin/gcc
+ 
+-will cause the specified gcc to be used as the C compiler (unless it is
++causes the specified 'gcc' to be used as the C compiler (unless it is
+ overridden in the site shell script).
+ 
+-`configure' Invocation
++Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
++Autoconf limitation.  Until the limitation is lifted, you can use this
++workaround:
++
++     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
++
++'configure' Invocation
+ ======================
+ 
+-   `configure' recognizes the following options to control how it
++   'configure' recognizes the following options to control how it
+ operates.
+ 
+-`--help'
+-`-h'
+-     Print a summary of the options to `configure', and exit.
++'--help'
++'-h'
++     Print a summary of all of the options to 'configure', and exit.
++
++'--help=short'
++'--help=recursive'
++     Print a summary of the options unique to this package's
++     'configure', and exit.  The 'short' variant lists options used only
++     in the top level, while the 'recursive' variant lists options also
++     present in any nested packages.
+ 
+-`--version'
+-`-V'
+-     Print the version of Autoconf used to generate the `configure'
++'--version'
++'-V'
++     Print the version of Autoconf used to generate the 'configure'
+      script, and exit.
+ 
+-`--cache-file=FILE'
++'--cache-file=FILE'
+      Enable the cache: use and save the results of the tests in FILE,
+-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
++     traditionally 'config.cache'.  FILE defaults to '/dev/null' to
+      disable caching.
+ 
+-`--config-cache'
+-`-C'
+-     Alias for `--cache-file=config.cache'.
++'--config-cache'
++'-C'
++     Alias for '--cache-file=config.cache'.
+ 
+-`--quiet'
+-`--silent'
+-`-q'
++'--quiet'
++'--silent'
++'-q'
+      Do not print messages saying which checks are being made.  To
+-     suppress all normal output, redirect it to `/dev/null' (any error
++     suppress all normal output, redirect it to '/dev/null' (any error
+      messages will still be shown).
+ 
+-`--srcdir=DIR'
++'--srcdir=DIR'
+      Look for the package's source code in directory DIR.  Usually
+-     `configure' can determine that directory automatically.
++     'configure' can determine that directory automatically.
++
++'--prefix=DIR'
++     Use DIR as the installation prefix.  *note Installation Names:: for
++     more details, including other options available for fine-tuning the
++     installation locations.
+ 
+-`configure' also accepts some other, not widely useful, options.  Run
+-`configure --help' for more details.
++'--no-create'
++'-n'
++     Run the configure checks, but stop before creating any output
++     files.
+ 
++'configure' also accepts some other, not widely useful, options.  Run
++'configure --help' for more details.
+diff --git a/autogen.sh b/autogen.sh
+deleted file mode 100755
+index 6def96dd..00000000
+--- a/autogen.sh
++++ /dev/null
+@@ -1,51 +0,0 @@
+-#! /bin/sh
+-
+-echo aclocal...
+-(aclocal --version) < /dev/null > /dev/null 2>&1 || {
+-    echo aclocal not found
+-    exit 1
+-}
+-
+-aclocal -I ./scripts -I . ${ACLOCAL_FLAGS} || exit 1
+-
+-echo autoheader...
+-(autoheader --version) < /dev/null > /dev/null 2>&1 || {
+-    echo autoheader not found
+-    exit 1
+-}
+-
+-autoheader || exit 1
+-
+-echo -n "libtoolize... "
+-if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then
+-    echo "using glibtoolize"
+-    glibtoolize --automake --copy --force || exit 1
+-
+-elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then
+-    echo "using libtoolize"
+-    libtoolize --automake --copy --force || exit 1
+-
+-else
+-    echo "libtoolize nor glibtoolize not found"
+-    exit 1
+-fi
+-
+-echo automake...
+-(automake --version) < /dev/null > /dev/null 2>&1 || {
+-    echo automake not found
+-    exit 1
+-}
+-
+-automake --add-missing --copy --foreign || exit 1
+-
+-echo autoconf...
+-(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+-    echo autoconf not found
+-    exit 1
+-}
+-
+-autoconf || exit 1
+-
+-echo ready to configure
+-
+-exit 0
+diff --git a/configure.ac b/configure.ac
+index a4f051e4..453e2936 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,10 +1,14 @@
+-AC_INIT(libtorrent, 0.13.8, sundell.software@gmail.com)
++AC_INIT([[libtorrent]],[[0.13.8]],[[sundell.software@gmail.com]])
+ 
+-LT_INIT([disable-static])
++AC_CONFIG_HEADERS([config.h])
++AC_CONFIG_MACRO_DIRS([scripts])
++AM_INIT_AUTOMAKE([serial-tests subdir-objects foreign])
++
++LT_INIT([[disable-static]])
+ 
+ dnl Find a better way to do this
+-AC_DEFINE(PEER_NAME, "-lt0D80-", Identifier that is part of the default peer id)
+-AC_DEFINE(PEER_VERSION, "lt\x0D\x80", 4 byte client and version identifier for DHT)
++AC_DEFINE([[PEER_NAME]], [["-lt0D80-"]], [[Identifier that is part of the default peer id.]])
++AC_DEFINE([[PEER_VERSION]], [["lt\x0D\x80"]], [[4 byte client and version identifier for DHT.]])
+ 
+ LIBTORRENT_CURRENT=21
+ LIBTORRENT_REVISION=0
+@@ -17,9 +21,6 @@ AC_SUBST(LIBTORRENT_CURRENT)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_INFO)
+ AC_SUBST(LIBTORRENT_INTERFACE_VERSION_NO)
+ 
+-AM_INIT_AUTOMAKE([serial-tests subdir-objects])
+-AC_CONFIG_HEADERS(config.h)
+-
+ AC_PROG_CXX
+ AC_SYS_LARGEFILE
+ 
+@@ -29,14 +30,14 @@ AC_C_BIGENDIAN(
+   AC_MSG_ERROR([Could not determine endianness])
+ )
+ 
++AX_CXX_COMPILE_STDCXX(14, noext, mandatory)
++
+ RAK_CHECK_CFLAGS
+ RAK_CHECK_CXXFLAGS
+ RAK_ENABLE_DEBUG
+ RAK_ENABLE_EXTRA_DEBUG
+ RAK_ENABLE_WERROR
+ 
+-RAK_CHECK_CXX11
+-
+ TORRENT_ENABLE_ALIGNED
+ TORRENT_ENABLE_INTERRUPT_SOCKET
+ 
+@@ -55,7 +56,7 @@ TORRENT_WITHOUT_STATFS
+ TORRENT_WITH_INOTIFY
+ 
+ AC_ARG_ENABLE(attribute-visibility,
+-  AC_HELP_STRING([--disable-attribute-visibility], [disable symbol visibility attribute [[default=enable]]]),
++  AS_HELP_STRING([--disable-attribute-visibility],[disable symbol visibility attribute [[default=enable]]]),
+   [
+     if test "$enableval" = "yes"; then
+       CC_ATTRIBUTE_VISIBILITY
+@@ -65,7 +66,7 @@ AC_ARG_ENABLE(attribute-visibility,
+   ])
+ 
+ AC_ARG_ENABLE(execinfo,
+-  AC_HELP_STRING([--disable-execinfo], [disable libexecinfo [[default=enable]]]),
++  AS_HELP_STRING([--disable-execinfo],[disable libexecinfo [[default=enable]]]),
+   [
+     if test "$enableval" = "yes"; then
+       AX_EXECINFO
+@@ -109,12 +110,13 @@ CC_ATTRIBUTE_UNUSED(
+   AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
+ )
+ 
+-AC_OUTPUT([
++AC_CONFIG_FILES([
+ 	libtorrent.pc
+ 	Makefile
+ 	src/Makefile
+ 	src/torrent/Makefile
+-        test/Makefile
+-        test/torrent/net/Makefile
+-        test/net/Makefile
++  test/Makefile
++  test/torrent/net/Makefile
++  test/net/Makefile
+ ])
++AC_OUTPUT
+diff --git a/scripts/ax_check_zlib.m4 b/scripts/ax_check_zlib.m4
+old mode 100644
+new mode 100755
+index ae5705f6..1a168430
+--- a/scripts/ax_check_zlib.m4
++++ b/scripts/ax_check_zlib.m4
+@@ -1,5 +1,5 @@
+ # ===========================================================================
+-#       http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html
++#      https://www.gnu.org/software/autoconf-archive/ax_check_zlib.html
+ # ===========================================================================
+ #
+ # SYNOPSIS
+@@ -47,7 +47,7 @@
+ #   Public License for more details.
+ #
+ #   You should have received a copy of the GNU General Public License along
+-#   with this program. If not, see <http://www.gnu.org/licenses/>.
++#   with this program. If not, see <https://www.gnu.org/licenses/>.
+ #
+ #   As a special exception, the respective Autoconf Macro's copyright owner
+ #   gives unlimited permission to copy, distribute and modify the configure
+@@ -62,7 +62,7 @@
+ #   modified version of the Autoconf Macro, you may extend this special
+ #   exception to the GPL to apply to your modified version as well.
+ 
+-#serial 14
++#serial 16
+ 
+ AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB])
+ AC_DEFUN([AX_CHECK_ZLIB],
+@@ -108,11 +108,10 @@ then
+         LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
+         CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
+   fi
+-  AC_LANG_SAVE
+-  AC_LANG_C
++  AC_LANG_PUSH([C])
+   AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no])
+   AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no])
+-  AC_LANG_RESTORE
++  AC_LANG_POP([C])
+   if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes"
+   then
+     #
+diff --git a/scripts/ax_cxx_compile_stdcxx.m4 b/scripts/ax_cxx_compile_stdcxx.m4
+new file mode 100755
+index 00000000..9413da62
+--- /dev/null
++++ b/scripts/ax_cxx_compile_stdcxx.m4
+@@ -0,0 +1,962 @@
++# ===========================================================================
++#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
++# ===========================================================================
++#
++# SYNOPSIS
++#
++#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
++#
++# DESCRIPTION
++#
++#   Check for baseline language coverage in the compiler for the specified
++#   version of the C++ standard.  If necessary, add switches to CXX and
++#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
++#   or '14' (for the C++14 standard).
++#
++#   The second argument, if specified, indicates whether you insist on an
++#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
++#   -std=c++11).  If neither is specified, you get whatever works, with
++#   preference for no added switch, and then for an extended mode.
++#
++#   The third argument, if specified 'mandatory' or if left unspecified,
++#   indicates that baseline support for the specified C++ standard is
++#   required and that the macro should error out if no mode with that
++#   support is found.  If specified 'optional', then configuration proceeds
++#   regardless, after defining HAVE_CXX${VERSION} if and only if a
++#   supporting mode is found.
++#
++# LICENSE
++#
++#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
++#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
++#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
++#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
++#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
++#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
++#   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
++#   Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
++#   Copyright (c) 2020 Jason Merrill <jason@redhat.com>
++#
++#   Copying and distribution of this file, with or without modification, are
++#   permitted in any medium without royalty provided the copyright notice
++#   and this notice are preserved.  This file is offered as-is, without any
++#   warranty.
++
++#serial 12
++
++dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
++dnl  (serial version number 13).
++
++AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
++  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
++        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
++        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
++        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
++  m4_if([$2], [], [],
++        [$2], [ext], [],
++        [$2], [noext], [],
++        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
++  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
++        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
++        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
++        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
++  AC_LANG_PUSH([C++])dnl
++  ac_success=no
++
++  m4_if([$2], [], [dnl
++    AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
++		   ax_cv_cxx_compile_cxx$1,
++      [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
++        [ax_cv_cxx_compile_cxx$1=yes],
++        [ax_cv_cxx_compile_cxx$1=no])])
++    if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
++      ac_success=yes
++    fi])
++
++  m4_if([$2], [noext], [], [dnl
++  if test x$ac_success = xno; then
++    for alternative in ${ax_cxx_compile_alternatives}; do
++      switch="-std=gnu++${alternative}"
++      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
++      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
++                     $cachevar,
++        [ac_save_CXX="$CXX"
++         CXX="$CXX $switch"
++         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
++          [eval $cachevar=yes],
++          [eval $cachevar=no])
++         CXX="$ac_save_CXX"])
++      if eval test x\$$cachevar = xyes; then
++        CXX="$CXX $switch"
++        if test -n "$CXXCPP" ; then
++          CXXCPP="$CXXCPP $switch"
++        fi
++        ac_success=yes
++        break
++      fi
++    done
++  fi])
++
++  m4_if([$2], [ext], [], [dnl
++  if test x$ac_success = xno; then
++    dnl HP's aCC needs +std=c++11 according to:
++    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
++    dnl Cray's crayCC needs "-h std=c++11"
++    for alternative in ${ax_cxx_compile_alternatives}; do
++      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
++        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
++        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
++                       $cachevar,
++          [ac_save_CXX="$CXX"
++           CXX="$CXX $switch"
++           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
++            [eval $cachevar=yes],
++            [eval $cachevar=no])
++           CXX="$ac_save_CXX"])
++        if eval test x\$$cachevar = xyes; then
++          CXX="$CXX $switch"
++          if test -n "$CXXCPP" ; then
++            CXXCPP="$CXXCPP $switch"
++          fi
++          ac_success=yes
++          break
++        fi
++      done
++      if test x$ac_success = xyes; then
++        break
++      fi
++    done
++  fi])
++  AC_LANG_POP([C++])
++  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
++    if test x$ac_success = xno; then
++      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
++    fi
++  fi
++  if test x$ac_success = xno; then
++    HAVE_CXX$1=0
++    AC_MSG_NOTICE([No compiler with C++$1 support was found])
++  else
++    HAVE_CXX$1=1
++    AC_DEFINE(HAVE_CXX$1,1,
++              [define if the compiler supports basic C++$1 syntax])
++  fi
++  AC_SUBST(HAVE_CXX$1)
++])
++
++
++dnl  Test body for checking C++11 support
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
++)
++
++
++dnl  Test body for checking C++14 support
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
++)
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
++  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
++)
++
++dnl  Tests for new features in C++11
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
++
++// If the compiler admits that it is not ready for C++11, why torture it?
++// Hopefully, this will speed up the test.
++
++#ifndef __cplusplus
++
++#error "This is not a C++ compiler"
++
++#elif __cplusplus < 201103L
++
++#error "This is not a C++11 compiler"
++
++#else
++
++namespace cxx11
++{
++
++  namespace test_static_assert
++  {
++
++    template <typename T>
++    struct check
++    {
++      static_assert(sizeof(int) <= sizeof(T), "not big enough");
++    };
++
++  }
++
++  namespace test_final_override
++  {
++
++    struct Base
++    {
++      virtual ~Base() {}
++      virtual void f() {}
++    };
++
++    struct Derived : public Base
++    {
++      virtual ~Derived() override {}
++      virtual void f() override {}
++    };
++
++  }
++
++  namespace test_double_right_angle_brackets
++  {
++
++    template < typename T >
++    struct check {};
++
++    typedef check<void> single_type;
++    typedef check<check<void>> double_type;
++    typedef check<check<check<void>>> triple_type;
++    typedef check<check<check<check<void>>>> quadruple_type;
++
++  }
++
++  namespace test_decltype
++  {
++
++    int
++    f()
++    {
++      int a = 1;
++      decltype(a) b = 2;
++      return a + b;
++    }
++
++  }
++
++  namespace test_type_deduction
++  {
++
++    template < typename T1, typename T2 >
++    struct is_same
++    {
++      static const bool value = false;
++    };
++
++    template < typename T >
++    struct is_same<T, T>
++    {
++      static const bool value = true;
++    };
++
++    template < typename T1, typename T2 >
++    auto
++    add(T1 a1, T2 a2) -> decltype(a1 + a2)
++    {
++      return a1 + a2;
++    }
++
++    int
++    test(const int c, volatile int v)
++    {
++      static_assert(is_same<int, decltype(0)>::value == true, "");
++      static_assert(is_same<int, decltype(c)>::value == false, "");
++      static_assert(is_same<int, decltype(v)>::value == false, "");
++      auto ac = c;
++      auto av = v;
++      auto sumi = ac + av + 'x';
++      auto sumf = ac + av + 1.0;
++      static_assert(is_same<int, decltype(ac)>::value == true, "");
++      static_assert(is_same<int, decltype(av)>::value == true, "");
++      static_assert(is_same<int, decltype(sumi)>::value == true, "");
++      static_assert(is_same<int, decltype(sumf)>::value == false, "");
++      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
++      return (sumf > 0.0) ? sumi : add(c, v);
++    }
++
++  }
++
++  namespace test_noexcept
++  {
++
++    int f() { return 0; }
++    int g() noexcept { return 0; }
++
++    static_assert(noexcept(f()) == false, "");
++    static_assert(noexcept(g()) == true, "");
++
++  }
++
++  namespace test_constexpr
++  {
++
++    template < typename CharT >
++    unsigned long constexpr
++    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
++    {
++      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
++    }
++
++    template < typename CharT >
++    unsigned long constexpr
++    strlen_c(const CharT *const s) noexcept
++    {
++      return strlen_c_r(s, 0UL);
++    }
++
++    static_assert(strlen_c("") == 0UL, "");
++    static_assert(strlen_c("1") == 1UL, "");
++    static_assert(strlen_c("example") == 7UL, "");
++    static_assert(strlen_c("another\0example") == 7UL, "");
++
++  }
++
++  namespace test_rvalue_references
++  {
++
++    template < int N >
++    struct answer
++    {
++      static constexpr int value = N;
++    };
++
++    answer<1> f(int&)       { return answer<1>(); }
++    answer<2> f(const int&) { return answer<2>(); }
++    answer<3> f(int&&)      { return answer<3>(); }
++
++    void
++    test()
++    {
++      int i = 0;
++      const int c = 0;
++      static_assert(decltype(f(i))::value == 1, "");
++      static_assert(decltype(f(c))::value == 2, "");
++      static_assert(decltype(f(0))::value == 3, "");
++    }
++
++  }
++
++  namespace test_uniform_initialization
++  {
++
++    struct test
++    {
++      static const int zero {};
++      static const int one {1};
++    };
++
++    static_assert(test::zero == 0, "");
++    static_assert(test::one == 1, "");
++
++  }
++
++  namespace test_lambdas
++  {
++
++    void
++    test1()
++    {
++      auto lambda1 = [](){};
++      auto lambda2 = lambda1;
++      lambda1();
++      lambda2();
++    }
++
++    int
++    test2()
++    {
++      auto a = [](int i, int j){ return i + j; }(1, 2);
++      auto b = []() -> int { return '0'; }();
++      auto c = [=](){ return a + b; }();
++      auto d = [&](){ return c; }();
++      auto e = [a, &b](int x) mutable {
++        const auto identity = [](int y){ return y; };
++        for (auto i = 0; i < a; ++i)
++          a += b--;
++        return x + identity(a + b);
++      }(0);
++      return a + b + c + d + e;
++    }
++
++    int
++    test3()
++    {
++      const auto nullary = [](){ return 0; };
++      const auto unary = [](int x){ return x; };
++      using nullary_t = decltype(nullary);
++      using unary_t = decltype(unary);
++      const auto higher1st = [](nullary_t f){ return f(); };
++      const auto higher2nd = [unary](nullary_t f1){
++        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
++      };
++      return higher1st(nullary) + higher2nd(nullary)(unary);
++    }
++
++  }
++
++  namespace test_variadic_templates
++  {
++
++    template <int...>
++    struct sum;
++
++    template <int N0, int... N1toN>
++    struct sum<N0, N1toN...>
++    {
++      static constexpr auto value = N0 + sum<N1toN...>::value;
++    };
++
++    template <>
++    struct sum<>
++    {
++      static constexpr auto value = 0;
++    };
++
++    static_assert(sum<>::value == 0, "");
++    static_assert(sum<1>::value == 1, "");
++    static_assert(sum<23>::value == 23, "");
++    static_assert(sum<1, 2>::value == 3, "");
++    static_assert(sum<5, 5, 11>::value == 21, "");
++    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
++
++  }
++
++  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
++  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
++  // because of this.
++  namespace test_template_alias_sfinae
++  {
++
++    struct foo {};
++
++    template<typename T>
++    using member = typename T::member_type;
++
++    template<typename T>
++    void func(...) {}
++
++    template<typename T>
++    void func(member<T>*) {}
++
++    void test();
++
++    void test() { func<foo>(0); }
++
++  }
++
++}  // namespace cxx11
++
++#endif  // __cplusplus >= 201103L
++
++]])
++
++
++dnl  Tests for new features in C++14
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
++
++// If the compiler admits that it is not ready for C++14, why torture it?
++// Hopefully, this will speed up the test.
++
++#ifndef __cplusplus
++
++#error "This is not a C++ compiler"
++
++#elif __cplusplus < 201402L
++
++#error "This is not a C++14 compiler"
++
++#else
++
++namespace cxx14
++{
++
++  namespace test_polymorphic_lambdas
++  {
++
++    int
++    test()
++    {
++      const auto lambda = [](auto&&... args){
++        const auto istiny = [](auto x){
++          return (sizeof(x) == 1UL) ? 1 : 0;
++        };
++        const int aretiny[] = { istiny(args)... };
++        return aretiny[0];
++      };
++      return lambda(1, 1L, 1.0f, '1');
++    }
++
++  }
++
++  namespace test_binary_literals
++  {
++
++    constexpr auto ivii = 0b0000000000101010;
++    static_assert(ivii == 42, "wrong value");
++
++  }
++
++  namespace test_generalized_constexpr
++  {
++
++    template < typename CharT >
++    constexpr unsigned long
++    strlen_c(const CharT *const s) noexcept
++    {
++      auto length = 0UL;
++      for (auto p = s; *p; ++p)
++        ++length;
++      return length;
++    }
++
++    static_assert(strlen_c("") == 0UL, "");
++    static_assert(strlen_c("x") == 1UL, "");
++    static_assert(strlen_c("test") == 4UL, "");
++    static_assert(strlen_c("another\0test") == 7UL, "");
++
++  }
++
++  namespace test_lambda_init_capture
++  {
++
++    int
++    test()
++    {
++      auto x = 0;
++      const auto lambda1 = [a = x](int b){ return a + b; };
++      const auto lambda2 = [a = lambda1(x)](){ return a; };
++      return lambda2();
++    }
++
++  }
++
++  namespace test_digit_separators
++  {
++
++    constexpr auto ten_million = 100'000'000;
++    static_assert(ten_million == 100000000, "");
++
++  }
++
++  namespace test_return_type_deduction
++  {
++
++    auto f(int& x) { return x; }
++    decltype(auto) g(int& x) { return x; }
++
++    template < typename T1, typename T2 >
++    struct is_same
++    {
++      static constexpr auto value = false;
++    };
++
++    template < typename T >
++    struct is_same<T, T>
++    {
++      static constexpr auto value = true;
++    };
++
++    int
++    test()
++    {
++      auto x = 0;
++      static_assert(is_same<int, decltype(f(x))>::value, "");
++      static_assert(is_same<int&, decltype(g(x))>::value, "");
++      return x;
++    }
++
++  }
++
++}  // namespace cxx14
++
++#endif  // __cplusplus >= 201402L
++
++]])
++
++
++dnl  Tests for new features in C++17
++
++m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
++
++// If the compiler admits that it is not ready for C++17, why torture it?
++// Hopefully, this will speed up the test.
++
++#ifndef __cplusplus
++
++#error "This is not a C++ compiler"
++
++#elif __cplusplus < 201703L
++
++#error "This is not a C++17 compiler"
++
++#else
++
++#include <initializer_list>
++#include <utility>
++#include <type_traits>
++
++namespace cxx17
++{
++
++  namespace test_constexpr_lambdas
++  {
++
++    constexpr int foo = [](){return 42;}();
++
++  }
++
++  namespace test::nested_namespace::definitions
++  {
++
++  }
++
++  namespace test_fold_expression
++  {
++
++    template<typename... Args>
++    int multiply(Args... args)
++    {
++      return (args * ... * 1);
++    }
++
++    template<typename... Args>
++    bool all(Args... args)
++    {
++      return (args && ...);
++    }
++
++  }
++
++  namespace test_extended_static_assert
++  {
++
++    static_assert (true);
++
++  }
++
++  namespace test_auto_brace_init_list
++  {
++
++    auto foo = {5};
++    auto bar {5};
++
++    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
++    static_assert(std::is_same<int, decltype(bar)>::value);
++  }
++
++  namespace test_typename_in_template_template_parameter
++  {
++
++    template<template<typename> typename X> struct D;
++
++  }
++
++  namespace test_fallthrough_nodiscard_maybe_unused_attributes
++  {
++
++    int f1()
++    {
++      return 42;
++    }
++
++    [[nodiscard]] int f2()
++    {
++      [[maybe_unused]] auto unused = f1();
++
++      switch (f1())
++      {
++      case 17:
++        f1();
++        [[fallthrough]];
++      case 42:
++        f1();
++      }
++      return f1();
++    }
++
++  }
++
++  namespace test_extended_aggregate_initialization
++  {
++
++    struct base1
++    {
++      int b1, b2 = 42;
++    };
++
++    struct base2
++    {
++      base2() {
++        b3 = 42;
++      }
++      int b3;
++    };
++
++    struct derived : base1, base2
++    {
++        int d;
++    };
++
++    derived d1 {{1, 2}, {}, 4};  // full initialization
++    derived d2 {{}, {}, 4};      // value-initialized bases
++
++  }
++
++  namespace test_general_range_based_for_loop
++  {
++
++    struct iter
++    {
++      int i;
++
++      int& operator* ()
++      {
++        return i;
++      }
++
++      const int& operator* () const
++      {
++        return i;
++      }
++
++      iter& operator++()
++      {
++        ++i;
++        return *this;
++      }
++    };
++
++    struct sentinel
++    {
++      int i;
++    };
++
++    bool operator== (const iter& i, const sentinel& s)
++    {
++      return i.i == s.i;
++    }
++
++    bool operator!= (const iter& i, const sentinel& s)
++    {
++      return !(i == s);
++    }
++
++    struct range
++    {
++      iter begin() const
++      {
++        return {0};
++      }
++
++      sentinel end() const
++      {
++        return {5};
++      }
++    };
++
++    void f()
++    {
++      range r {};
++
++      for (auto i : r)
++      {
++        [[maybe_unused]] auto v = i;
++      }
++    }
++
++  }
++
++  namespace test_lambda_capture_asterisk_this_by_value
++  {
++
++    struct t
++    {
++      int i;
++      int foo()
++      {
++        return [*this]()
++        {
++          return i;
++        }();
++      }
++    };
++
++  }
++
++  namespace test_enum_class_construction
++  {
++
++    enum class byte : unsigned char
++    {};
++
++    byte foo {42};
++
++  }
++
++  namespace test_constexpr_if
++  {
++
++    template <bool cond>
++    int f ()
++    {
++      if constexpr(cond)
++      {
++        return 13;
++      }
++      else
++      {
++        return 42;
++      }
++    }
++
++  }
++
++  namespace test_selection_statement_with_initializer
++  {
++
++    int f()
++    {
++      return 13;
++    }
++
++    int f2()
++    {
++      if (auto i = f(); i > 0)
++      {
++        return 3;
++      }
++
++      switch (auto i = f(); i + 4)
++      {
++      case 17:
++        return 2;
++
++      default:
++        return 1;
++      }
++    }
++
++  }
++
++  namespace test_template_argument_deduction_for_class_templates
++  {
++
++    template <typename T1, typename T2>
++    struct pair
++    {
++      pair (T1 p1, T2 p2)
++        : m1 {p1},
++          m2 {p2}
++      {}
++
++      T1 m1;
++      T2 m2;
++    };
++
++    void f()
++    {
++      [[maybe_unused]] auto p = pair{13, 42u};
++    }
++
++  }
++
++  namespace test_non_type_auto_template_parameters
++  {
++
++    template <auto n>
++    struct B
++    {};
++
++    B<5> b1;
++    B<'a'> b2;
++
++  }
++
++  namespace test_structured_bindings
++  {
++
++    int arr[2] = { 1, 2 };
++    std::pair<int, int> pr = { 1, 2 };
++
++    auto f1() -> int(&)[2]
++    {
++      return arr;
++    }
++
++    auto f2() -> std::pair<int, int>&
++    {
++      return pr;
++    }
++
++    struct S
++    {
++      int x1 : 2;
++      volatile double y1;
++    };
++
++    S f3()
++    {
++      return {};
++    }
++
++    auto [ x1, y1 ] = f1();
++    auto& [ xr1, yr1 ] = f1();
++    auto [ x2, y2 ] = f2();
++    auto& [ xr2, yr2 ] = f2();
++    const auto [ x3, y3 ] = f3();
++
++  }
++
++  namespace test_exception_spec_type_system
++  {
++
++    struct Good {};
++    struct Bad {};
++
++    void g1() noexcept;
++    void g2();
++
++    template<typename T>
++    Bad
++    f(T*, T*);
++
++    template<typename T1, typename T2>
++    Good
++    f(T1*, T2*);
++
++    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
++
++  }
++
++  namespace test_inline_variables
++  {
++
++    template<class T> void f(T)
++    {}
++
++    template<class T> inline T g(T)
++    {
++      return T{};
++    }
++
++    template<> inline void f<>(int)
++    {}
++
++    template<> int g<>(int)
++    {
++      return 5;
++    }
++
++  }
++
++}  // namespace cxx17
++
++#endif  // __cplusplus < 201703L
++
++]])
+diff --git a/scripts/ax_cxx_compile_stdcxx_0x.m4 b/scripts/ax_cxx_compile_stdcxx_0x.m4
+deleted file mode 100644
+index 5ff134a6..00000000
+--- a/scripts/ax_cxx_compile_stdcxx_0x.m4
++++ /dev/null
+@@ -1,106 +0,0 @@
+-# ============================================================================
+-#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_0x.html
+-# ============================================================================
+-#
+-# SYNOPSIS
+-#
+-#   AX_CXX_COMPILE_STDCXX_0X
+-#
+-# DESCRIPTION
+-#
+-#   Check for baseline language coverage in the compiler for the C++0x
+-#   standard.
+-#
+-# LICENSE
+-#
+-#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+-#
+-#   Copying and distribution of this file, with or without modification, are
+-#   permitted in any medium without royalty provided the copyright notice
+-#   and this notice are preserved. This file is offered as-is, without any
+-#   warranty.
+-
+-#serial 7 (+1)
+-
+-AU_ALIAS([AC_CXX_COMPILE_STDCXX_0X], [AX_CXX_COMPILE_STDCXX_0X])
+-AC_DEFUN([AX_CXX_COMPILE_STDCXX_0X], [
+-  AC_CACHE_CHECK(if g++ supports C++0x features without additional flags,
+-  ax_cv_cxx_compile_cxx0x_native,
+-  [AC_LANG_SAVE
+-  AC_LANG_CPLUSPLUS
+-  AC_TRY_COMPILE([
+-  template <typename T>
+-    struct check
+-    {
+-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+-    };
+-
+-    typedef check<check<bool>> right_angle_brackets;
+-
+-    int a;
+-    decltype(a) b;
+-
+-    typedef check<int> check_type;
+-    check_type c;
+-    check_type&& cr = static_cast<check_type&&>(c);],,
+-  ax_cv_cxx_compile_cxx0x_native=yes, ax_cv_cxx_compile_cxx0x_native=no)
+-  AC_LANG_RESTORE
+-  ])
+-
+-  AC_CACHE_CHECK(if g++ supports C++0x features with -std=c++0x,
+-  ax_cv_cxx_compile_cxx0x_cxx,
+-  [AC_LANG_SAVE
+-  AC_LANG_CPLUSPLUS
+-  ac_save_CXXFLAGS="$CXXFLAGS"
+-  CXXFLAGS="$CXXFLAGS -std=c++0x"
+-  AC_TRY_COMPILE([
+-  template <typename T>
+-    struct check
+-    {
+-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+-    };
+-
+-    typedef check<check<bool>> right_angle_brackets;
+-
+-    int a;
+-    decltype(a) b;
+-
+-    typedef check<int> check_type;
+-    check_type c;
+-    check_type&& cr = static_cast<check_type&&>(c);],,
+-  ax_cv_cxx_compile_cxx0x_cxx=yes, ax_cv_cxx_compile_cxx0x_cxx=no)
+-  CXXFLAGS="$ac_save_CXXFLAGS"
+-  AC_LANG_RESTORE
+-  ])
+-
+-  AC_CACHE_CHECK(if g++ supports C++0x features with -std=gnu++0x,
+-  ax_cv_cxx_compile_cxx0x_gxx,
+-  [AC_LANG_SAVE
+-  AC_LANG_CPLUSPLUS
+-  ac_save_CXXFLAGS="$CXXFLAGS"
+-  CXXFLAGS="$CXXFLAGS -std=gnu++0x"
+-  AC_TRY_COMPILE([
+-  template <typename T>
+-    struct check
+-    {
+-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+-    };
+-
+-    typedef check<check<bool>> right_angle_brackets;
+-
+-    int a;
+-    decltype(a) b;
+-
+-    typedef check<int> check_type;
+-    check_type c;
+-    check_type&& cr = static_cast<check_type&&>(c);],,
+-  ax_cv_cxx_compile_cxx0x_gxx=yes, ax_cv_cxx_compile_cxx0x_gxx=no)
+-  CXXFLAGS="$ac_save_CXXFLAGS"
+-  AC_LANG_RESTORE
+-  ])
+-
+-  if test "$ax_cv_cxx_compile_cxx0x_cxx" = yes; then  
+-    AC_DEFINE(HAVE_STDCXX_0X,, [Define if compiler supports C++0x features.])
+-    CXXFLAGS="$CXXFLAGS -std=c++0x"
+-  fi
+-])
+diff --git a/scripts/ax_cxx_compile_stdcxx_11.m4 b/scripts/ax_cxx_compile_stdcxx_11.m4
+deleted file mode 100644
+index 5cf70eb6..00000000
+--- a/scripts/ax_cxx_compile_stdcxx_11.m4
++++ /dev/null
+@@ -1,147 +0,0 @@
+-# ============================================================================
+-#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+-# ============================================================================
+-#
+-# SYNOPSIS
+-#
+-#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+-#
+-# DESCRIPTION
+-#
+-#   Check for baseline language coverage in the compiler for the C++11
+-#   standard; if necessary, add switches to CXXFLAGS to enable support.
+-#
+-#   The first argument, if specified, indicates whether you insist on an
+-#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+-#   -std=c++11).  If neither is specified, you get whatever works, with
+-#   preference for an extended mode.
+-#
+-#   The second argument, if specified 'mandatory' or if left unspecified,
+-#   indicates that baseline C++11 support is required and that the macro
+-#   should error out if no mode with that support is found.  If specified
+-#   'optional', then configuration proceeds regardless, after defining
+-#   HAVE_CXX11 if and only if a supporting mode is found.
+-#
+-# LICENSE
+-#
+-#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+-#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+-#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+-#   Copyright (c) 2014 Alexey Sokolov <sokolov@google.com>
+-#   Copyright (c) 2014 Jari Sundell <sundell.software@gmail.com>
+-#
+-#   Copying and distribution of this file, with or without modification, are
+-#   permitted in any medium without royalty provided the copyright notice
+-#   and this notice are preserved. This file is offered as-is, without any
+-#   warranty.
+-
+-#serial 5
+-
+-m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
+-  template <typename T>
+-    struct check
+-    {
+-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+-    };
+-
+-    struct Base {
+-    virtual void f() {}
+-    };
+-    struct Child : public Base {
+-    virtual void f() override {}
+-    };
+-
+-    typedef check<check<bool>> right_angle_brackets;
+-
+-    int a;
+-    decltype(a) b;
+-
+-    typedef check<int> check_type;
+-    check_type c;
+-    check_type&& cr = static_cast<check_type&&>(c);
+-
+-    auto d = a;
+-    auto l = [](){};
+-
+-    void unused() {
+-      l();
+-    }
+-]])
+-
+-AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+-  m4_if([$1], [], [],
+-        [$1], [ext], [],
+-        [$1], [noext], [],
+-        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+-  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+-        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+-        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+-        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
+-  AC_LANG_PUSH([C++])dnl
+-  ac_success=no
+-  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+-  ax_cv_cxx_compile_cxx11,
+-  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+-    [ax_cv_cxx_compile_cxx11=yes],
+-    [ax_cv_cxx_compile_cxx11=no])])
+-  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+-    ac_success=yes
+-  fi
+-
+-  m4_if([$1], [noext], [], [dnl
+-  if test x$ac_success = xno; then
+-    for switch in -std=gnu++11 -std=gnu++0x; do
+-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+-                     $cachevar,
+-        [ac_save_CXXFLAGS="$CXXFLAGS"
+-         CXXFLAGS="$CXXFLAGS $switch"
+-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+-          [eval $cachevar=yes],
+-          [eval $cachevar=no])
+-         CXXFLAGS="$ac_save_CXXFLAGS"])
+-      if eval test x\$$cachevar = xyes; then
+-        CXXFLAGS="$CXXFLAGS $switch"
+-        ac_success=yes
+-        break
+-      fi
+-    done
+-  fi])
+-
+-  m4_if([$1], [ext], [], [dnl
+-  if test x$ac_success = xno; then
+-    for switch in -std=c++11 -std=c++0x; do
+-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+-                     $cachevar,
+-        [ac_save_CXXFLAGS="$CXXFLAGS"
+-         CXXFLAGS="$CXXFLAGS $switch"
+-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+-          [eval $cachevar=yes],
+-          [eval $cachevar=no])
+-         CXXFLAGS="$ac_save_CXXFLAGS"])
+-      if eval test x\$$cachevar = xyes; then
+-        CXXFLAGS="$CXXFLAGS $switch"
+-        ac_success=yes
+-        break
+-      fi
+-    done
+-  fi])
+-  AC_LANG_POP([C++])
+-  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+-    if test x$ac_success = xno; then
+-      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+-    fi
+-  else
+-    if test x$ac_success = xno; then
+-      HAVE_CXX11=0
+-      AC_MSG_NOTICE([No compiler with C++11 support was found])
+-    else
+-      HAVE_CXX11=1
+-      AC_DEFINE(HAVE_CXX11,1,
+-                [define if the compiler supports basic C++11 syntax])
+-    fi
+-
+-    AC_SUBST(HAVE_CXX11)
+-  fi
+-])
+diff --git a/scripts/ax_pthread.m4 b/scripts/ax_pthread.m4
+old mode 100644
+new mode 100755
+index 27f2533c..9f35d139
+--- a/scripts/ax_pthread.m4
++++ b/scripts/ax_pthread.m4
+@@ -1,5 +1,5 @@
+ # ===========================================================================
+-#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
++#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html
+ # ===========================================================================
+ #
+ # SYNOPSIS
+@@ -14,24 +14,28 @@
+ #   flags that are needed. (The user can also force certain compiler
+ #   flags/libs to be tested by setting these environment variables.)
+ #
+-#   Also sets PTHREAD_CC to any special C compiler that is needed for
+-#   multi-threaded programs (defaults to the value of CC otherwise). (This
+-#   is necessary on AIX to use the special cc_r compiler alias.)
++#   Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
++#   needed for multi-threaded programs (defaults to the value of CC
++#   respectively CXX otherwise). (This is necessary on e.g. AIX to use the
++#   special cc_r/CC_r compiler alias.)
+ #
+ #   NOTE: You are assumed to not only compile your program with these flags,
+-#   but also link it with them as well. e.g. you should link with
++#   but also to link with them as well. For example, you might link with
+ #   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
++#   $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+ #
+-#   If you are only building threads programs, you may wish to use these
++#   If you are only building threaded programs, you may wish to use these
+ #   variables in your default LIBS, CFLAGS, and CC:
+ #
+ #     LIBS="$PTHREAD_LIBS $LIBS"
+ #     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++#     CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ #     CC="$PTHREAD_CC"
++#     CXX="$PTHREAD_CXX"
+ #
+ #   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+-#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+-#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
++#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
++#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+ #
+ #   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+ #   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+@@ -55,6 +59,7 @@
+ #
+ #   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+ #   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
++#   Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
+ #
+ #   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
+@@ -67,7 +72,7 @@
+ #   Public License for more details.
+ #
+ #   You should have received a copy of the GNU General Public License along
+-#   with this program. If not, see <http://www.gnu.org/licenses/>.
++#   with this program. If not, see <https://www.gnu.org/licenses/>.
+ #
+ #   As a special exception, the respective Autoconf Macro's copyright owner
+ #   gives unlimited permission to copy, distribute and modify the configure
+@@ -82,35 +87,41 @@
+ #   modified version of the Autoconf Macro, you may extend this special
+ #   exception to the GPL to apply to your modified version as well.
+ 
+-#serial 17
++#serial 31
+ 
+ AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+ AC_DEFUN([AX_PTHREAD], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
++AC_REQUIRE([AC_PROG_CC])
++AC_REQUIRE([AC_PROG_SED])
+ AC_LANG_PUSH([C])
+ ax_pthread_ok=no
+ 
+ # We used to check for pthread.h first, but this fails if pthread.h
+-# requires special compiler flags (e.g. on True64 or Sequent).
++# requires special compiler flags (e.g. on Tru64 or Sequent).
+ # It gets checked for in the link test anyway.
+ 
+ # First of all, check if the user has set any of the PTHREAD_LIBS,
+ # etcetera environment variables, and if threads linking works using
+ # them:
+-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+-        save_CFLAGS="$CFLAGS"
++if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
++        ax_pthread_save_CC="$CC"
++        ax_pthread_save_CFLAGS="$CFLAGS"
++        ax_pthread_save_LIBS="$LIBS"
++        AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
++        AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
+         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+-        save_LIBS="$LIBS"
+         LIBS="$PTHREAD_LIBS $LIBS"
+-        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+-        AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
+-        AC_MSG_RESULT($ax_pthread_ok)
+-        if test x"$ax_pthread_ok" = xno; then
++        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
++        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
++        AC_MSG_RESULT([$ax_pthread_ok])
++        if test "x$ax_pthread_ok" = "xno"; then
+                 PTHREAD_LIBS=""
+                 PTHREAD_CFLAGS=""
+         fi
+-        LIBS="$save_LIBS"
+-        CFLAGS="$save_CFLAGS"
++        CC="$ax_pthread_save_CC"
++        CFLAGS="$ax_pthread_save_CFLAGS"
++        LIBS="$ax_pthread_save_LIBS"
+ fi
+ 
+ # We must check for the threads library under a number of different
+@@ -118,12 +129,14 @@ fi
+ # (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+ # libraries is broken (non-POSIX).
+ 
+-# Create a list of thread flags to try.  Items starting with a "-" are
+-# C compiler flags, and other items are library names, except for "none"
+-# which indicates that we try without any flags at all, and "pthread-config"
+-# which is a program returning the flags for the Pth emulation library.
++# Create a list of thread flags to try. Items with a "," contain both
++# C compiler flags (before ",") and linker flags (after ","). Other items
++# starting with a "-" are C compiler flags, and remaining items are
++# library names, except for "none" which indicates that we try without
++# any flags at all, and "pthread-config" which is a program returning
++# the flags for the Pth emulation library.
+ 
+-ax_pthread_flags="none pthreads -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
++ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+ 
+ # The ordering *is* (sometimes) important.  Some notes on the
+ # individual items follow:
+@@ -132,68 +145,163 @@ ax_pthread_flags="none pthreads -Kthread -kthread lthread -pthread -pthreads -mt
+ # none: in case threads are in libc; should be tried before -Kthread and
+ #       other compiler flags to prevent continual compiler warnings
+ # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+-# -pthreads: Solaris/gcc
+-# -mthreads: Mingw32/gcc, Lynx/gcc
++# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
++#           (Note: HP C rejects this with "bad form for `-t' option")
++# -pthreads: Solaris/gcc (Note: HP C also rejects)
+ # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+-#      doesn't hurt to check since this sometimes defines pthreads too;
+-#      also defines -D_REENTRANT)
+-#      ... -mt is also the pthreads flag for HP/aCC
++#      doesn't hurt to check since this sometimes defines pthreads and
++#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
++#      is present but should not be used directly; and before -mthreads,
++#      because the compiler interprets this as "-mt" + "-hreads")
++# -mthreads: Mingw32/gcc, Lynx/gcc
+ # pthread: Linux, etcetera
+ # --thread-safe: KAI C++
+ # pthread-config: use pthread-config program (for GNU Pth library)
+ 
+-case "${host_cpu}-${host_os}" in
+-        *solaris*)
++case $host_os in
++
++        freebsd*)
++
++        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
++        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
++
++        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
++        ;;
++
++        hpux*)
++
++        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
++        # multi-threading and also sets -lpthread."
++
++        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
++        ;;
++
++        openedition*)
++
++        # IBM z/OS requires a feature-test macro to be defined in order to
++        # enable POSIX threads at all, so give the user a hint if this is
++        # not set. (We don't define these ourselves, as they can affect
++        # other portions of the system API in unpredictable ways.)
++
++        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
++            [
++#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
++             AX_PTHREAD_ZOS_MISSING
++#            endif
++            ],
++            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
++        ;;
++
++        solaris*)
+ 
+         # On Solaris (at least, for some versions), libc contains stubbed
+         # (non-functional) versions of the pthreads routines, so link-based
+-        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+-        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+-        # a function called by this macro, so we could check for that, but
+-        # who knows whether they'll stub that too in a future libc.)  So,
+-        # we'll just look for -pthreads and -lpthread first:
++        # tests will erroneously succeed. (N.B.: The stubs are missing
++        # pthread_cleanup_push, or rather a function called by this macro,
++        # so we could check for that, but who knows whether they'll stub
++        # that too in a future libc.)  So we'll check first for the
++        # standard Solaris way of linking pthreads (-mt -lpthread).
+ 
+-        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
++        ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
+         ;;
++esac
+ 
+-        *-darwin*)
+-        ax_pthread_flags="none -pthread $ax_pthread_flags"
++# Are we compiling with Clang?
++
++AC_CACHE_CHECK([whether $CC is Clang],
++    [ax_cv_PTHREAD_CLANG],
++    [ax_cv_PTHREAD_CLANG=no
++     # Note that Autoconf sets GCC=yes for Clang as well as GCC
++     if test "x$GCC" = "xyes"; then
++        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
++            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
++#            if defined(__clang__) && defined(__llvm__)
++             AX_PTHREAD_CC_IS_CLANG
++#            endif
++            ],
++            [ax_cv_PTHREAD_CLANG=yes])
++     fi
++    ])
++ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
++
++
++# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
++
++# Note that for GCC and Clang -pthread generally implies -lpthread,
++# except when -nostdlib is passed.
++# This is problematic using libtool to build C++ shared libraries with pthread:
++# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
++# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
++# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
++# To solve this, first try -pthread together with -lpthread for GCC
++
++AS_IF([test "x$GCC" = "xyes"],
++      [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
++
++# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
++
++AS_IF([test "x$ax_pthread_clang" = "xyes"],
++      [ax_pthread_flags="-pthread,-lpthread -pthread"])
++
++
++# The presence of a feature test macro requesting re-entrant function
++# definitions is, on some systems, a strong hint that pthreads support is
++# correctly enabled
++
++case $host_os in
++        darwin* | hpux* | linux* | osf* | solaris*)
++        ax_pthread_check_macro="_REENTRANT"
++        ;;
++
++        aix*)
++        ax_pthread_check_macro="_THREAD_SAFE"
++        ;;
++
++        *)
++        ax_pthread_check_macro="--"
+         ;;
+ esac
++AS_IF([test "x$ax_pthread_check_macro" = "x--"],
++      [ax_pthread_check_cond=0],
++      [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
++
+ 
+-if test x"$ax_pthread_ok" = xno; then
+-for flag in $ax_pthread_flags; do
++if test "x$ax_pthread_ok" = "xno"; then
++for ax_pthread_try_flag in $ax_pthread_flags; do
+ 
+-        case $flag in
++        case $ax_pthread_try_flag in
+                 none)
+                 AC_MSG_CHECKING([whether pthreads work without any flags])
+                 ;;
+ 
++                *,*)
++                PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
++                PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
++                AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
++                ;;
++
+                 -*)
+-                AC_MSG_CHECKING([whether pthreads work with $flag])
+-                PTHREAD_CFLAGS="$flag"
++                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
++                PTHREAD_CFLAGS="$ax_pthread_try_flag"
+                 ;;
+ 
+                 pthread-config)
+-                AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
+-                if test x"$ax_pthread_config" = xno; then continue; fi
++                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
++                AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
+                 PTHREAD_CFLAGS="`pthread-config --cflags`"
+                 PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                 ;;
+ 
+                 *)
+-                AC_MSG_CHECKING([for the pthreads library -l$flag])
+-                PTHREAD_LIBS="-l$flag"
++                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
++                PTHREAD_LIBS="-l$ax_pthread_try_flag"
+                 ;;
+         esac
+ 
+-        save_LIBS="$LIBS"
+-        save_CFLAGS="$CFLAGS"
+-        LIBS="$PTHREAD_LIBS $LIBS"
++        ax_pthread_save_CFLAGS="$CFLAGS"
++        ax_pthread_save_LIBS="$LIBS"
+         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++        LIBS="$PTHREAD_LIBS $LIBS"
+ 
+         # Check for various functions.  We must include pthread.h,
+         # since some functions may be macros.  (On the Sequent, we
+@@ -204,8 +312,18 @@ for flag in $ax_pthread_flags; do
+         # pthread_cleanup_push because it is one of the few pthread
+         # functions on Solaris that doesn't have a non-functional libc stub.
+         # We try pthread_create on general principles.
++
+         AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+-                        static void routine(void *a) { a = 0; }
++#                       if $ax_pthread_check_cond
++#                        error "$ax_pthread_check_macro must be defined"
++#                       endif
++                        static void *some_global = NULL;
++                        static void routine(void *a)
++                          {
++                             /* To avoid any unused-parameter or
++                                unused-but-set-parameter warning.  */
++                             some_global = a;
++                          }
+                         static void *start_routine(void *a) { return a; }],
+                        [pthread_t th; pthread_attr_t attr;
+                         pthread_create(&th, 0, start_routine, 0);
+@@ -213,93 +331,188 @@ for flag in $ax_pthread_flags; do
+                         pthread_attr_init(&attr);
+                         pthread_cleanup_push(routine, 0);
+                         pthread_cleanup_pop(0) /* ; */])],
+-                [ax_pthread_ok=yes],
+-                [])
++            [ax_pthread_ok=yes],
++            [])
+ 
+-        LIBS="$save_LIBS"
+-        CFLAGS="$save_CFLAGS"
++        CFLAGS="$ax_pthread_save_CFLAGS"
++        LIBS="$ax_pthread_save_LIBS"
+ 
+-        AC_MSG_RESULT($ax_pthread_ok)
+-        if test "x$ax_pthread_ok" = xyes; then
+-                break;
+-        fi
++        AC_MSG_RESULT([$ax_pthread_ok])
++        AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
+ 
+         PTHREAD_LIBS=""
+         PTHREAD_CFLAGS=""
+ done
+ fi
+ 
++
++# Clang needs special handling, because older versions handle the -pthread
++# option in a rather... idiosyncratic way
++
++if test "x$ax_pthread_clang" = "xyes"; then
++
++        # Clang takes -pthread; it has never supported any other flag
++
++        # (Note 1: This will need to be revisited if a system that Clang
++        # supports has POSIX threads in a separate library.  This tends not
++        # to be the way of modern systems, but it's conceivable.)
++
++        # (Note 2: On some systems, notably Darwin, -pthread is not needed
++        # to get POSIX threads support; the API is always present and
++        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
++        # -pthread does define _REENTRANT, and while the Darwin headers
++        # ignore this macro, third-party headers might not.)
++
++        # However, older versions of Clang make a point of warning the user
++        # that, in an invocation where only linking and no compilation is
++        # taking place, the -pthread option has no effect ("argument unused
++        # during compilation").  They expect -pthread to be passed in only
++        # when source code is being compiled.
++        #
++        # Problem is, this is at odds with the way Automake and most other
++        # C build frameworks function, which is that the same flags used in
++        # compilation (CFLAGS) are also used in linking.  Many systems
++        # supported by AX_PTHREAD require exactly this for POSIX threads
++        # support, and in fact it is often not straightforward to specify a
++        # flag that is used only in the compilation phase and not in
++        # linking.  Such a scenario is extremely rare in practice.
++        #
++        # Even though use of the -pthread flag in linking would only print
++        # a warning, this can be a nuisance for well-run software projects
++        # that build with -Werror.  So if the active version of Clang has
++        # this misfeature, we search for an option to squash it.
++
++        AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
++            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
++            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
++             # Create an alternate version of $ac_link that compiles and
++             # links in two steps (.c -> .o, .o -> exe) instead of one
++             # (.c -> exe), because the warning occurs only in the second
++             # step
++             ax_pthread_save_ac_link="$ac_link"
++             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
++             ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
++             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
++             ax_pthread_save_CFLAGS="$CFLAGS"
++             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
++                AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
++                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
++                ac_link="$ax_pthread_save_ac_link"
++                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
++                    [ac_link="$ax_pthread_2step_ac_link"
++                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
++                         [break])
++                    ])
++             done
++             ac_link="$ax_pthread_save_ac_link"
++             CFLAGS="$ax_pthread_save_CFLAGS"
++             AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
++             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
++            ])
++
++        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
++                no | unknown) ;;
++                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
++        esac
++
++fi # $ax_pthread_clang = yes
++
++
++
+ # Various other checks:
+-if test "x$ax_pthread_ok" = xyes; then
+-        save_LIBS="$LIBS"
+-        LIBS="$PTHREAD_LIBS $LIBS"
+-        save_CFLAGS="$CFLAGS"
++if test "x$ax_pthread_ok" = "xyes"; then
++        ax_pthread_save_CFLAGS="$CFLAGS"
++        ax_pthread_save_LIBS="$LIBS"
+         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++        LIBS="$PTHREAD_LIBS $LIBS"
+ 
+         # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+-        AC_MSG_CHECKING([for joinable pthread attribute])
+-        attr_name=unknown
+-        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+-            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+-                           [int attr = $attr; return attr /* ; */])],
+-                [attr_name=$attr; break],
+-                [])
+-        done
+-        AC_MSG_RESULT($attr_name)
+-        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+-            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+-                               [Define to necessary symbol if this constant
+-                                uses a non-standard name on your system.])
+-        fi
++        AC_CACHE_CHECK([for joinable pthread attribute],
++            [ax_cv_PTHREAD_JOINABLE_ATTR],
++            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
++             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
++                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
++                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],
++                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
++                                [])
++             done
++            ])
++        AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
++               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
++               test "x$ax_pthread_joinable_attr_defined" != "xyes"],
++              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
++                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],
++                                  [Define to necessary symbol if this constant
++                                   uses a non-standard name on your system.])
++               ax_pthread_joinable_attr_defined=yes
++              ])
+ 
+-        AC_MSG_CHECKING([if more special flags are required for pthreads])
+-        flag=no
+-        case "${host_cpu}-${host_os}" in
+-            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+-            *-osf* | *-hpux*) flag="-D_REENTRANT";;
+-            *solaris*)
+-            if test "$GCC" = "yes"; then
+-                flag="-D_REENTRANT"
+-            else
+-                flag="-mt -D_REENTRANT"
+-            fi
+-            ;;
+-        esac
+-        AC_MSG_RESULT(${flag})
+-        if test "x$flag" != xno; then
+-            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+-        fi
++        AC_CACHE_CHECK([whether more special flags are required for pthreads],
++            [ax_cv_PTHREAD_SPECIAL_FLAGS],
++            [ax_cv_PTHREAD_SPECIAL_FLAGS=no
++             case $host_os in
++             solaris*)
++             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
++             ;;
++             esac
++            ])
++        AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
++               test "x$ax_pthread_special_flags_added" != "xyes"],
++              [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
++               ax_pthread_special_flags_added=yes])
+ 
+         AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+-            ax_cv_PTHREAD_PRIO_INHERIT, [
+-                AC_LINK_IFELSE([
+-                    AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
+-                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+-                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
++            [ax_cv_PTHREAD_PRIO_INHERIT],
++            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
++                                             [[int i = PTHREAD_PRIO_INHERIT;
++                                               return i;]])],
++                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],
++                            [ax_cv_PTHREAD_PRIO_INHERIT=no])
+             ])
+-        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+-            AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
++        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
++               test "x$ax_pthread_prio_inherit_defined" != "xyes"],
++              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
++               ax_pthread_prio_inherit_defined=yes
++              ])
+ 
+-        LIBS="$save_LIBS"
+-        CFLAGS="$save_CFLAGS"
++        CFLAGS="$ax_pthread_save_CFLAGS"
++        LIBS="$ax_pthread_save_LIBS"
+ 
+-        # More AIX lossage: must compile with xlc_r or cc_r
+-        if test x"$GCC" != xyes; then
+-          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+-        else
+-          PTHREAD_CC=$CC
++        # More AIX lossage: compile with *_r variant
++        if test "x$GCC" != "xyes"; then
++            case $host_os in
++                aix*)
++                AS_CASE(["x/$CC"],
++                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
++                    [#handle absolute path differently from PATH based program lookup
++                     AS_CASE(["x$CC"],
++                         [x/*],
++                         [
++			   AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
++			   AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
++			 ],
++                         [
++			   AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
++			   AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
++			 ]
++                     )
++                    ])
++                ;;
++            esac
+         fi
+-else
+-        PTHREAD_CC="$CC"
+ fi
+ 
+-AC_SUBST(PTHREAD_LIBS)
+-AC_SUBST(PTHREAD_CFLAGS)
+-AC_SUBST(PTHREAD_CC)
++test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
++test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
++
++AC_SUBST([PTHREAD_LIBS])
++AC_SUBST([PTHREAD_CFLAGS])
++AC_SUBST([PTHREAD_CC])
++AC_SUBST([PTHREAD_CXX])
+ 
+ # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+-if test x"$ax_pthread_ok" = xyes; then
+-        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
++if test "x$ax_pthread_ok" = "xyes"; then
++        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+         :
+ else
+         ax_pthread_ok=no
+diff --git a/scripts/checks.m4 b/scripts/checks.m4
+index 915a5011..b9095cee 100644
+--- a/scripts/checks.m4
++++ b/scripts/checks.m4
+@@ -21,7 +21,7 @@ AC_DEFUN([TORRENT_CHECK_XFS], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_XFS], [
+   AC_ARG_WITH(xfs,
+-    AC_HELP_STRING([--without-xfs], [do not check for XFS filesystem support]),
++    AS_HELP_STRING([--without-xfs],[do not check for XFS filesystem support]),
+     [
+        if test "$withval" = "yes"; then
+         TORRENT_CHECK_XFS
+@@ -34,7 +34,7 @@ AC_DEFUN([TORRENT_WITHOUT_XFS], [
+ 
+ AC_DEFUN([TORRENT_WITH_XFS], [
+   AC_ARG_WITH(xfs,
+-    AC_HELP_STRING([--with-xfs], [check for XFS filesystem support]),
++    AS_HELP_STRING([--with-xfs],[check for XFS filesystem support]),
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_XFS
+@@ -63,7 +63,7 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_EPOLL], [
+   AC_ARG_WITH(epoll,
+-    AC_HELP_STRING([--without-epoll], [do not check for epoll support]),
++    AS_HELP_STRING([--without-epoll],[do not check for epoll support]),
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_EPOLL
+@@ -134,7 +134,7 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
+ 
+ AC_DEFUN([TORRENT_WITH_KQUEUE], [
+   AC_ARG_WITH(kqueue,
+-    AC_HELP_STRING([--with-kqueue], [enable kqueue [[default=no]]]),
++    AS_HELP_STRING([--with-kqueue],[enable kqueue [[default=no]]]),
+     [
+         if test "$withval" = "yes"; then
+           TORRENT_CHECK_KQUEUE
+@@ -145,7 +145,7 @@ AC_DEFUN([TORRENT_WITH_KQUEUE], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
+   AC_ARG_WITH(kqueue,
+-    AC_HELP_STRING([--without-kqueue], [do not check for kqueue support]),
++    AS_HELP_STRING([--without-kqueue],[do not check for kqueue support]),
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_KQUEUE
+@@ -158,7 +158,7 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
+   AC_ARG_WITH(variable-fdset,
+-    AC_HELP_STRING([--without-variable-fdset], [do not use non-portable variable sized fd_set's]),
++    AS_HELP_STRING([--without-variable-fdset],[do not use non-portable variable sized fd_set's]),
+     [
+       if test "$withval" = "yes"; then
+         AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
+@@ -172,14 +172,13 @@ AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
+ AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
+   AC_MSG_CHECKING(for fallocate)
+ 
+-  AC_TRY_LINK([#define _GNU_SOURCE
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define _GNU_SOURCE
+                #include <fcntl.h>
+-              ],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
+-              ],
+-    [
++              ]], [[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
++              ]])],[
+       AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.)
+       AC_MSG_RESULT(yes)
+-    ], [
++    ],[
+       AC_MSG_RESULT(no)
+     ])
+ ])
+@@ -188,13 +187,12 @@ AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
+ AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
+   AC_MSG_CHECKING(for posix_fallocate)
+ 
+-  AC_TRY_LINK([#include <fcntl.h>
+-              ],[ posix_fallocate(0, 0, 0);
+-              ],
+-    [
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>
++              ]], [[ posix_fallocate(0, 0, 0);
++              ]])],[
+       AC_DEFINE(USE_POSIX_FALLOCATE, 1, posix_fallocate supported.)
+       AC_MSG_RESULT(yes)
+-    ], [
++    ],[
+       AC_MSG_RESULT(no)
+     ])
+ ])
+@@ -202,7 +200,7 @@ AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
+ 
+ AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
+   AC_ARG_WITH(posix-fallocate,
+-    AC_HELP_STRING([--with-posix-fallocate], [check for and use posix_fallocate to allocate files]),
++    AS_HELP_STRING([--with-posix-fallocate],[check for and use posix_fallocate to allocate files]),
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_POSIX_FALLOCATE
+@@ -215,8 +213,7 @@ AC_DEFUN([TORRENT_CHECK_STATVFS], [
+ 
+   AC_MSG_CHECKING(for statvfs)
+ 
+-  AC_TRY_LINK(
+-    [
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+       #if HAVE_SYS_VFS_H
+       #include <sys/vfs.h>
+       #endif
+@@ -226,12 +223,11 @@ AC_DEFUN([TORRENT_CHECK_STATVFS], [
+       #if HAVE_SYS_STATFS_H
+       #include <sys/statfs.h>
+       #endif
+-    ],[
++    ]], [[
+       struct statvfs s; fsblkcnt_t c;
+       statvfs("", &s);
+       fstatvfs(0, &s);
+-    ],
+-    [
++    ]])],[
+       AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
+       AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
+       AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
+@@ -240,8 +236,7 @@ AC_DEFUN([TORRENT_CHECK_STATVFS], [
+       AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
+       AC_MSG_RESULT(ok)
+       have_stat_vfs=yes
+-    ],
+-    [
++    ],[
+       AC_MSG_RESULT(no)
+       have_stat_vfs=no
+     ])
+@@ -252,8 +247,7 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
+ 
+   AC_MSG_CHECKING(for statfs)
+ 
+-  AC_TRY_LINK(
+-    [
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+       #if HAVE_SYS_STATFS_H
+       #include <sys/statfs.h>
+       #endif
+@@ -263,12 +257,11 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
+       #if HAVE_SYS_MOUNT_H
+       #include <sys/mount.h>
+       #endif
+-    ],[
++    ]], [[
+       struct statfs s;
+       statfs("", &s);
+       fstatfs(0, &s);
+-    ],
+-    [
++    ]])],[
+       AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
+       AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
+       AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
+@@ -277,8 +270,7 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
+       AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
+       AC_MSG_RESULT(ok)
+       have_stat_vfs=yes
+-    ],
+-    [
++    ],[
+       AC_MSG_RESULT(no)
+       have_stat_vfs=no
+     ])
+@@ -296,7 +288,7 @@ AC_DEFUN([TORRENT_DISABLED_STATFS], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
+   AC_ARG_WITH(statvfs,
+-    AC_HELP_STRING([--without-statvfs], [don't try to use statvfs to find free diskspace]),
++    AS_HELP_STRING([--without-statvfs],[don't try to use statvfs to find free diskspace]),
+     [
+       if test "$withval" = "yes"; then
+         TORRENT_CHECK_STATVFS
+@@ -311,7 +303,7 @@ AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
+ 
+ AC_DEFUN([TORRENT_WITHOUT_STATFS], [
+   AC_ARG_WITH(statfs,
+-    AC_HELP_STRING([--without-statfs], [don't try to use statfs to find free diskspace]),
++    AS_HELP_STRING([--without-statfs],[don't try to use statfs to find free diskspace]),
+     [
+       if test "$have_stat_vfs" = "no"; then
+         if test "$withval" = "yes"; then
+@@ -333,7 +325,7 @@ AC_DEFUN([TORRENT_WITHOUT_STATFS], [
+ 
+ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
+   AC_ARG_WITH(address-space,
+-    AC_HELP_STRING([--with-address-space=MB], [change the default address space size [[default=1024mb]]]),
++    AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
+     [
+       if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
+         AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
+@@ -354,7 +346,7 @@ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
+ 
+ AC_DEFUN([TORRENT_WITH_FASTCGI], [
+   AC_ARG_WITH(fastcgi,
+-    AC_HELP_STRING([--with-fastcgi=PATH], [enable FastCGI RPC support (DO NOT USE)]),
++    AS_HELP_STRING([--with-fastcgi=PATH],[enable FastCGI RPC support (DO NOT USE)]),
+     [
+       AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
+ 
+@@ -365,13 +357,10 @@ AC_DEFUN([TORRENT_WITH_FASTCGI], [
+         CXXFLAGS="$CXXFLAGS"
+ 	LIBS="$LIBS -lfcgi"        
+ 
+-        AC_TRY_LINK(
+-        [ #include <fcgiapp.h>
+-        ],[ FCGX_Init(); ],
+-        [
++        AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
++        ]], [[ FCGX_Init(); ]])],[
+           AC_MSG_RESULT(ok)
+-        ],
+-        [
++        ],[
+           AC_MSG_RESULT(not found)
+           AC_MSG_ERROR(Could not compile FastCGI test.)
+         ])
+@@ -382,13 +371,10 @@ AC_DEFUN([TORRENT_WITH_FASTCGI], [
+         CXXFLAGS="$CXXFLAGS -I$withval/include"
+ 	LIBS="$LIBS -lfcgi -L$withval/lib"
+ 
+-        AC_TRY_LINK(
+-        [ #include <fcgiapp.h>
+-        ],[ FCGX_Init(); ],
+-        [
++        AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
++        ]], [[ FCGX_Init(); ]])],[
+           AC_MSG_RESULT(ok)
+-        ],
+-        [
++        ],[
+           AC_MSG_RESULT(not found)
+           AC_MSG_ERROR(Could not compile FastCGI test.)
+         ])
+@@ -403,7 +389,7 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
+   AC_MSG_CHECKING(for XMLRPC-C)
+ 
+   AC_ARG_WITH(xmlrpc-c,
+-    AC_HELP_STRING([--with-xmlrpc-c=PATH], [enable XMLRPC-C support]),
++    AS_HELP_STRING([--with-xmlrpc-c=PATH],[enable XMLRPC-C support]),
+   [
+     if test "$withval" = "no"; then
+       AC_MSG_RESULT(no)
+@@ -419,12 +405,10 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
+         CXXFLAGS="$CXXFLAGS `$xmlrpc_cc_prg --cflags server-util`"
+         LIBS="$LIBS `$xmlrpc_cc_prg server-util --libs`"
+ 
+-        AC_TRY_LINK(
+-        [ #include <xmlrpc-c/server.h>
+-        ],[ xmlrpc_registry_new(NULL); ],
+-        [
++        AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <xmlrpc-c/server.h>
++        ]], [[ xmlrpc_registry_new(NULL); ]])],[
+           AC_MSG_RESULT(ok)
+-        ], [
++        ],[
+           AC_MSG_RESULT(failed)
+           AC_MSG_ERROR(Could not compile XMLRPC-C test.)
+         ])
+@@ -466,23 +450,23 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
+ 
+   AC_MSG_CHECKING(for pthread_setname_np type)
+ 
+-  AC_TRY_LINK([
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+     #include <pthread.h>
+     #include <sys/types.h>
+-  ],[
++  ]], [[
+     pthread_t t;
+     pthread_setname_np(t, "foo");
+-  ],[
++  ]])],[
+     AC_DEFINE(HAS_PTHREAD_SETNAME_NP_GENERIC, 1, The function to set pthread name has a pthread_t argumet.)
+     AC_MSG_RESULT(generic)
+   ],[
+-    AC_TRY_LINK([
++    AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+       #include <pthread.h>
+       #include <sys/types.h>
+-    ],[
++    ]],[[
+       pthread_t t;
+       pthread_setname_np("foo");
+-    ],[
++    ]])],[
+       AC_DEFINE(HAS_PTHREAD_SETNAME_NP_DARWIN, 1, The function to set pthread name has no pthread argument.)
+       AC_MSG_RESULT(darwin)
+     ],[
+@@ -495,7 +479,7 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
+   AC_MSG_CHECKING([for pthread_setname_no])
+ 
+   AC_ARG_ENABLE(pthread-setname-np,
+-    AC_HELP_STRING([--disable-pthread-setname-np], [disable pthread_setname_np]),
++    AS_HELP_STRING([--disable-pthread-setname-np],[disable pthread_setname_np]),
+     [
+       if test "$enableval" = "no"; then
+         AC_MSG_RESULT(disabled)
+diff --git a/scripts/common.m4 b/scripts/common.m4
+index 55e8d66e..2f54402e 100644
+--- a/scripts/common.m4
++++ b/scripts/common.m4
+@@ -1,6 +1,7 @@
+ AC_DEFUN([TORRENT_WITH_SYSROOT], [
+   AC_ARG_WITH(sysroot,
+-    AC_HELP_STRING([--with-sysroot=PATH], [compile and link with a specific sysroot]),
++    AS_HELP_STRING([--with-sysroot=PATH],
++      [compile and link with a specific sysroot]),
+     [
+       AC_MSG_CHECKING(for sysroot)
+ 
+@@ -22,7 +23,8 @@ AC_DEFUN([TORRENT_WITH_SYSROOT], [
+ 
+ AC_DEFUN([TORRENT_ENABLE_ARCH], [
+   AC_ARG_ENABLE(arch,
+-    AC_HELP_STRING([--enable-arch=ARCH], [comma seprated list of architectures to compile for]),
++    AS_HELP_STRING([--enable-arch=ARCH],
++      [comma seprated list of architectures to compile for]),
+     [
+       AC_MSG_CHECKING(for target architectures)
+ 
+@@ -82,7 +84,8 @@ AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
+ 
+ AC_DEFUN([TORRENT_MINCORE], [
+   AC_ARG_ENABLE(mincore,
+-    AC_HELP_STRING([--disable-mincore], [disable mincore check [[default=enable]]]),
++    AS_HELP_STRING([--disable-mincore],
++      [disable mincore check [[default=enable]]]),
+     [
+       if test "$enableval" = "yes"; then
+         TORRENT_MINCORE_SIGNEDNESS()
+@@ -174,7 +177,8 @@ AC_DEFUN([TORRENT_CHECK_ALIGNED], [
+ 
+ AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
+   AC_ARG_ENABLE(aligned,
+-    AC_HELP_STRING([--enable-aligned], [enable alignment safe code [[default=check]]]),
++    AS_HELP_STRING([--enable-aligned],
++      [enable alignment safe code [[default=check]]]),
+     [
+         if test "$enableval" = "yes"; then
+           AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
+@@ -189,7 +193,8 @@ AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
+   AC_MSG_CHECKING([if instrumentation should be included])
+ 
+   AC_ARG_ENABLE(instrumentation,
+-    AC_HELP_STRING([--disable-instrumentation], [disable instrumentation [[default=enabled]]]),
++    AS_HELP_STRING([--disable-instrumentation],
++      [disable instrumentation [[default=enabled]]]),
+     [
+       if test "$enableval" = "yes"; then
+         AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
+@@ -206,7 +211,8 @@ AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
+ 
+ AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [
+   AC_ARG_ENABLE(interrupt-socket,
+-    AC_HELP_STRING([--enable-interrupt-socket], [enable interrupt socket [[default=no]]]),
++    AS_HELP_STRING([--enable-interrupt-socket],
++      [enable interrupt socket [[default=no]]]),
+     [
+       if test "$enableval" = "yes"; then
+         AC_DEFINE(USE_INTERRUPT_SOCKET, 1, Use interrupt socket instead of pthread_kill)
+@@ -214,3 +220,14 @@ AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [
+     ]
+   )
+ ])
++
++AC_DEFUN([TORRENT_DISABLE_IPV6], [
++  AC_ARG_ENABLE(ipv6,
++    AS_HELP_STRING([--enable-ipv6],
++      [enable ipv6 [[default=no]]]),
++    [
++        if test "$enableval" = "yes"; then
++            AC_DEFINE(RAK_USE_INET6, 1, enable ipv6 stuff)
++        fi
++    ])
++])
+diff --git a/scripts/rak_compiler.m4 b/scripts/rak_compiler.m4
+index 9a361bed..bc1572a3 100644
+--- a/scripts/rak_compiler.m4
++++ b/scripts/rak_compiler.m4
+@@ -26,7 +26,7 @@ AC_DEFUN([RAK_CHECK_CXXFLAGS], [
+ 
+ AC_DEFUN([RAK_ENABLE_DEBUG], [
+   AC_ARG_ENABLE(debug,
+-    AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]),
++    AS_HELP_STRING([--enable-debug],[enable debug information [[default=yes]]]),
+     [
+         if test "$enableval" = "yes"; then
+             CXXFLAGS="$CXXFLAGS -g -DDEBUG"
+@@ -41,7 +41,7 @@ AC_DEFUN([RAK_ENABLE_DEBUG], [
+ 
+ AC_DEFUN([RAK_ENABLE_WERROR], [
+   AC_ARG_ENABLE(werror,
+-    AC_HELP_STRING([--enable-werror], [enable the -Werror and -Wall flags [[default -Wall only]]]),
++    AS_HELP_STRING([--enable-werror],[enable the -Werror and -Wall flags [[default -Wall only]]]),
+     [
+         if test "$enableval" = "yes"; then
+            CXXFLAGS="$CXXFLAGS -Werror -Wall"
+@@ -54,7 +54,7 @@ AC_DEFUN([RAK_ENABLE_WERROR], [
+ 
+ AC_DEFUN([RAK_ENABLE_EXTRA_DEBUG], [
+   AC_ARG_ENABLE(extra-debug,
+-    AC_HELP_STRING([--enable-extra-debug], [enable extra debugging checks [[default=no]]]),
++    AS_HELP_STRING([--enable-extra-debug],[enable extra debugging checks [[default=no]]]),
+     [
+         if test "$enableval" = "yes"; then
+             AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
+diff --git a/scripts/rak_cxx.m4 b/scripts/rak_cxx.m4
+deleted file mode 100644
+index 0db61b83..00000000
+--- a/scripts/rak_cxx.m4
++++ /dev/null
+@@ -1,14 +0,0 @@
+-AC_DEFUN([RAK_CHECK_CXX11], [
+-  AC_ARG_ENABLE([c++0x],
+-    AC_HELP_STRING([--enable-c++0x], [compile with C++0x (unsupported)]),
+-    [
+-      if test "$enableval" = "yes"; then
+-        AX_CXX_COMPILE_STDCXX_0X
+-      else
+-        AX_CXX_COMPILE_STDCXX_11(noext)
+-      fi
+-    ],[
+-      AX_CXX_COMPILE_STDCXX_11(noext)
+-    ]
+-  )
+-])
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent/0044-Create-FUNDING.yml.patch b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0044-Create-FUNDING.yml.patch
new file mode 100644
index 000000000..b9378f503
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent/0044-Create-FUNDING.yml.patch
@@ -0,0 +1,29 @@ 
+From eca577e2a29d64251b5df1c69be53c5b1ffe6bde Mon Sep 17 00:00:00 2001
+From: Jari Sundell <sundell.software@gmail.com>
+Date: Thu, 8 Sep 2022 05:08:44 +0900
+Subject: [PATCH] Create FUNDING.yml
+
+---
+ .github/FUNDING.yml | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+ create mode 100644 .github/FUNDING.yml
+
+diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
+new file mode 100644
+index 00000000..ad5998e8
+--- /dev/null
++++ b/.github/FUNDING.yml
+@@ -0,0 +1,13 @@
++# These are supported funding model platforms
++
++github: [rakshasa]
++patreon: rtorrent
++open_collective: # Replace with a single Open Collective username
++ko_fi: # Replace with a single Ko-fi username
++tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
++community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
++liberapay: # Replace with a single Liberapay username
++issuehunt: # Replace with a single IssueHunt username
++otechie: # Replace with a single Otechie username
++lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
++custom: ['https://rakshasa.github.io/rtorrent/donate.html']
diff --git a/meta-oe/recipes-connectivity/libtorrent/libtorrent_git.bb b/meta-oe/recipes-connectivity/libtorrent/libtorrent_git.bb
index fec05571d..70c173be5 100644
--- a/meta-oe/recipes-connectivity/libtorrent/libtorrent_git.bb
+++ b/meta-oe/recipes-connectivity/libtorrent/libtorrent_git.bb
@@ -6,12 +6,57 @@  LIC_FILES_CHKSUM = "file://COPYING;md5=393a5ca445f6965873eca0259a17f833"
 
 DEPENDS = "zlib libsigc++-2.0 openssl cppunit"
 
-SRC_URI = "git://github.com/rakshasa/libtorrent;branch=master;protocol=https"
-SRCREV = "e60f222241319aaae482789517ad00ae9344bd13"
+SRC_URI = "git://github.com/rakshasa/libtorrent;branch=master;protocol=https \
+           file://0001-Fix-compilation-issue-with-gcc-v6.x-and-empty-CXXFLA.patch \
+           file://0002-Modfiy-gcc-v6.x-fix-for-empty-CXXFLAGS-See-10.patch \
+           file://0003-Add-space-to-fmt-str-in-log_gz_file_write.patch \
+           file://0004-IPv4-filter-enhancement-11IPv4-filter-enhancement-Cl.patch \
+           file://0005-Disable-extents-test-to-pass-TravisCI-See-11.patch \
+           file://0006-Bumped-version-to-0.13.7.patch \
+           file://0007-Added-support-for-openssl-1.1.patch \
+           file://0008-Use-AC_COMPILE-instead-of-AC_RUN-to-check-for-execin.patch \
+           file://0009-Modify-configure-to-prevent-unnecessary-kqueue-check.patch \
+           file://0010-Display-info-on-failed-tracker-bencode-parsing-See-9.patch \
+           file://0011-Strip-tags-also-when-displaying-info-on-failed-track.patch \
+           file://0012-Switch-to-C-11-MRT-RNG-for-random-bytes.patch \
+           file://0013-Prevent-loss-of-m_ipv6_socket-attribute-which-led-to.patch \
+           file://0014-If-during-socket-creation-AF_INET6-failes-initialize.patch \
+           file://0015-Fixes-https-github.com-rakshasa-rtorrent-issues-731.patch \
+           file://0016-Fix-honoring-throttle.min_peers-settings-in-rtorrent.patch \
+           file://0017-increase-piece-length-max.patch \
+           file://0018-Set-max-piece-size-512mb.patch \
+           file://0019-Fixed-compiler-warning.patch \
+           file://0020-Added-_GNU_SOURCE-to-fallocate-test.-neheb.patch \
+           file://0021-Fixed-diffie-hellman-implementation.patch \
+           file://0022-Increased-max-timeout-for-tracker-requests.patch \
+           file://0023-Close-log-files-when-reusing-a-name.patch \
+           file://0024-Bumped-to-version-0.13.8.patch \
+           file://0025-Allow-logs-to-be-appended-rather-than-overwritten.patch \
+           file://0026-Removed-log-append-function.-Added-append-parameter-.patch \
+           file://0027-Backport-changes-from-feature-bind.-200.patch \
+           file://0028-libtorrent.pc.in-add-Libs.Private-202.patch \
+           file://0029-Fix-for-inotify-missing-quickly-renamed-files-203.patch \
+           file://0030-Fix-compiler-warnings.-204.patch \
+           file://0031-Fix-log-format-so-GCC-can-check-it.-205.patch \
+           file://0032-Consolidate-make-script-to-optimize-build.-206.patch \
+           file://0033-Refactor-make-process.-207.patch \
+           file://0034-Changes-automake-required-files.patch \
+           file://0035-Replaced-custom-execinfo-autoconf-test.patch \
+           file://0036-Added-option-to-disable-pthread_setname_np.patch \
+           file://0037-Improved-backtrace-error-checking.patch \
+           file://0038-Fixed-issue-with-multiple-connections-from-NAT-not-w.patch \
+           file://0039-Added-disable-execinfo-option-to-configure.patch \
+           file://0040-Detect-ip-address.patch \
+           file://0041-Added-ipv6-options.patch \
+           file://0042-Removed-obsolete-files.patch \
+           file://0043-Updated-and-cleaned-up-automake.-224.patch \
+           file://0044-Create-FUNDING.yml.patch \
+           "
+SRCREV = "c167c5a9e0bcf0df23ae5efd91396aae0e37eb87"
 
 CVE_STATUS[CVE-2009-1760] = "backported-patch: patched in our product"
 
-PV = "0.13.8+git${SRCPV}"
+PV = "1"
 
 S = "${WORKDIR}/git"