summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO11
-rw-r--r--.gitignore3
-rw-r--r--PKGBUILD10
-rw-r--r--rtorrent-ipv6.patch688
4 files changed, 13 insertions, 699 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 5af9c5534bb1..d1e598d92f7b 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,21 +1,22 @@
+# Generated by mksrcinfo v8
+# Tue Feb 6 08:26:59 UTC 2018
pkgbase = rtorrent-ipv6
pkgdesc = Ncurses BitTorrent client based on libTorrent, with IPv6 patch
pkgver = 0.9.6
- pkgrel = 3
+ pkgrel = 4
url = http://rakshasa.github.io/rtorrent/
arch = i686
arch = x86_64
license = GPL
+ makedepends = git
depends = libtorrent-ipv6=0.13.6
depends = curl
depends = xmlrpc-c
depends = libsigc++
provides = rtorrent
conflicts = rtorrent
- source = rtorrent-0.9.6.tar.gz::https://github.com/rakshasa/rtorrent/archive/0.9.6.tar.gz
- source = rtorrent-ipv6.patch
- sha256sums = 8ca89ca9e8f0cf984198d030203087e93d24743dfa158091a5d225a70ca4c8cf
- sha256sums = 3bd16fe842362929a0018bbe4f0aec422a069800b675d04bc1b0246d21171028
+ source = rtorrent-0.9.6::git+https://github.com/rakshasa/rtorrent.git#commit=b088c1c657a646b0a8ca97a538a1ec9d719f5541
+ sha256sums = SKIP
pkgname = rtorrent-ipv6
diff --git a/.gitignore b/.gitignore
index 4601b3df4a5e..e6c228ccf8f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,6 @@ cookies
*.h
*.hpp
*.o
+
+*.log
+rtorrent-0.9.6/
diff --git a/PKGBUILD b/PKGBUILD
index a94819ad727b..204999afc777 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -7,22 +7,20 @@
_pkgname=rtorrent
pkgname=rtorrent-ipv6
pkgver=0.9.6
-pkgrel=3
+pkgrel=4
pkgdesc='Ncurses BitTorrent client based on libTorrent, with IPv6 patch'
url='http://rakshasa.github.io/rtorrent/'
license=('GPL')
arch=('i686' 'x86_64')
depends=('libtorrent-ipv6=0.13.6' 'curl' 'xmlrpc-c' 'libsigc++')
+makedepends=('git')
conflicts=("${_pkgname}")
provides=("${_pkgname}")
-source=("$_pkgname-$pkgver.tar.gz::https://github.com/rakshasa/${_pkgname}/archive/${pkgver}.tar.gz"
- "${_pkgname}-ipv6.patch")
-sha256sums=('8ca89ca9e8f0cf984198d030203087e93d24743dfa158091a5d225a70ca4c8cf'
- '3bd16fe842362929a0018bbe4f0aec422a069800b675d04bc1b0246d21171028')
+source=("$_pkgname-$pkgver::git+https://github.com/rakshasa/${_pkgname}.git#commit=b088c1c657a646b0a8ca97a538a1ec9d719f5541")
+sha256sums=('SKIP')
build() {
cd "${srcdir}/${_pkgname}-${pkgver}"
- patch -uNp1 -i "${srcdir}/${_pkgname}-ipv6.patch"
sed '/AM_PATH_CPPUNIT/d' -i configure.ac
./autogen.sh
diff --git a/rtorrent-ipv6.patch b/rtorrent-ipv6.patch
deleted file mode 100644
index 789a339831c9..000000000000
--- a/rtorrent-ipv6.patch
+++ /dev/null
@@ -1,688 +0,0 @@
-diff --git a/AUTHORS b/AUTHORS
-index 195fc22..f9bdb53 100644
---- a/AUTHORS
-+++ b/AUTHORS
-@@ -1 +1 @@
--Jari Sundell <jaris@ifi.uio.no>
-+Jari Sundell <sundell.software@gmail.com>
-diff --git a/README b/README
-index 6db6b25..1dbceaa 100644
---- a/README
-+++ b/README
-@@ -32,5 +32,10 @@ DEPENDENCIES
-
- CONTACT
-
-- Send bug reports, suggestions and patches to <jaris@ifi.uio.no> or
--to the mailinglist.
-+ Jari Sundell
-+
-+ Skomakerveien 33
-+ 3185 Skoppum, NORWAY
-+
-+ Send bug reports, suggestions and patches to
-+<sundell.software@gmail.com> or to the mailinglist.
-diff --git a/rak/socket_address.h b/rak/socket_address.h
-index 25fdb37..d1d5b72 100644
---- a/rak/socket_address.h
-+++ b/rak/socket_address.h
-@@ -109,13 +109,11 @@ public:
- const sockaddr* c_sockaddr() const { return &m_sockaddr; }
- const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
-
--#ifdef RAK_USE_INET6
- socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
- const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
-
- sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
- const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
--#endif
-
- // Copy a socket address which has the length 'length. Zero out any
- // extranous bytes and ensure it does not go beyond the size of this
-@@ -139,13 +137,11 @@ private:
- union {
- sockaddr m_sockaddr;
- sockaddr_in m_sockaddrInet;
--#ifdef RAK_USE_INET6
- sockaddr_in6 m_sockaddrInet6;
--#endif
- };
- };
-
--// Remeber to set the AF_INET.
-+// Remember to set the AF_INET.
-
- class socket_address_inet {
- public:
-@@ -184,6 +180,8 @@ public:
-
- const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
- const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
-+
-+ socket_address_inet6 to_mapped_address() const;
-
- bool operator == (const socket_address_inet& rhs) const;
- bool operator < (const socket_address_inet& rhs) const;
-@@ -192,48 +190,47 @@ private:
- struct sockaddr_in m_sockaddr;
- };
-
--// Unique key for the address, excluding port numbers etc.
--class socket_address_key {
-+class socket_address_inet6 {
- public:
--// socket_address_host_key() {}
-+ bool is_any() const { return is_port_any() && is_address_any(); }
-+ bool is_valid() const { return !is_port_any() && !is_address_any(); }
-+ bool is_port_any() const { return port() == 0; }
-+ bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
-
-- socket_address_key(const socket_address& sa) {
-- *this = sa;
-- }
-+ void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
-
-- socket_address_key& operator = (const socket_address& sa) {
-- if (sa.family() == 0) {
-- std::memset(this, 0, sizeof(socket_address_key));
-+ uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
-+ uint16_t port_n() const { return m_sockaddr.sin6_port; }
-+ void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
-+ void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
-
-- } else if (sa.family() == socket_address::af_inet) {
-- // Using hardware order as we use operator < to compare when
-- // using inet only.
-- m_addr.s_addr = sa.sa_inet()->address_h();
-+ in6_addr address() const { return m_sockaddr.sin6_addr; }
-+ const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; }
-+ std::string address_str() const;
-+ bool address_c_str(char* buf, socklen_t size) const;
-
-- } else {
-- // When we implement INET6 handling, embed the ipv4 address in
-- // the ipv6 address.
-- throw std::logic_error("socket_address_key(...) received an unsupported protocol family.");
-- }
-+ void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
-+ bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
-+ bool set_address_c_str(const char* a);
-
-- return *this;
-- }
-+ void set_address_any() { set_port(0); set_address(in6addr_any); }
-
--// socket_address_key& operator = (const socket_address_key& sa) {
--// }
-+ sa_family_t family() const { return m_sockaddr.sin6_family; }
-+ void set_family() { m_sockaddr.sin6_family = AF_INET6; }
-
-- bool operator < (const socket_address_key& sa) const {
-- // Compare the memory area instead.
-- return m_addr.s_addr < sa.m_addr.s_addr;
-- }
-+ sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
-+ sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
-+
-+ const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
-+ const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
-+
-+ socket_address normalize_address() const;
-+
-+ bool operator == (const socket_address_inet6& rhs) const;
-+ bool operator < (const socket_address_inet6& rhs) const;
-
- private:
-- union {
-- in_addr m_addr;
--// #ifdef RAK_USE_INET6
--// in_addr6 m_addr6;
--// #endif
-- };
-+ struct sockaddr_in6 m_sockaddr;
- };
-
- inline bool
-@@ -241,8 +238,8 @@ socket_address::is_valid() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->is_valid();
--// case af_inet6:
--// return sa_inet6().is_valid();
-+ case af_inet6:
-+ return sa_inet6()->is_valid();
- default:
- return false;
- }
-@@ -253,6 +250,8 @@ socket_address::is_bindable() const {
- switch (family()) {
- case af_inet:
- return !sa_inet()->is_address_any();
-+ case af_inet6:
-+ return !sa_inet6()->is_address_any();
- default:
- return false;
- }
-@@ -263,6 +262,8 @@ socket_address::is_address_any() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->is_address_any();
-+ case af_inet6:
-+ return sa_inet6()->is_address_any();
- default:
- return true;
- }
-@@ -273,6 +274,8 @@ socket_address::port() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->port();
-+ case af_inet6:
-+ return sa_inet6()->port();
- default:
- return 0;
- }
-@@ -283,6 +286,8 @@ socket_address::set_port(uint16_t p) {
- switch (family()) {
- case af_inet:
- return sa_inet()->set_port(p);
-+ case af_inet6:
-+ return sa_inet6()->set_port(p);
- default:
- break;
- }
-@@ -293,6 +298,8 @@ socket_address::address_str() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->address_str();
-+ case af_inet6:
-+ return sa_inet6()->address_str();
- default:
- return std::string();
- }
-@@ -303,6 +310,8 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
- switch (family()) {
- case af_inet:
- return sa_inet()->address_c_str(buf, size);
-+ case af_inet6:
-+ return sa_inet6()->address_c_str(buf, size);
- default:
- return false;
- }
-@@ -314,6 +323,10 @@ socket_address::set_address_c_str(const char* a) {
- sa_inet()->set_family();
- return true;
-
-+ } else if (sa_inet6()->set_address_c_str(a)) {
-+ sa_inet6()->set_family();
-+ return true;
-+
- } else {
- return false;
- }
-@@ -325,6 +338,8 @@ socket_address::length() const {
- switch(family()) {
- case af_inet:
- return sizeof(sockaddr_in);
-+ case af_inet6:
-+ return sizeof(sockaddr_in6);
- default:
- return 0;
- }
-@@ -349,8 +364,8 @@ socket_address::operator == (const socket_address& rhs) const {
- switch (family()) {
- case af_inet:
- return *sa_inet() == *rhs.sa_inet();
--// case af_inet6:
--// return *sa_inet6() == *rhs.sa_inet6();
-+ case af_inet6:
-+ return *sa_inet6() == *rhs.sa_inet6();
- default:
- throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
- }
-@@ -364,8 +379,8 @@ socket_address::operator < (const socket_address& rhs) const {
- switch (family()) {
- case af_inet:
- return *sa_inet() < *rhs.sa_inet();
--// case af_inet6:
--// return *sa_inet6() < *rhs.sa_inet6();
-+ case af_inet6:
-+ return *sa_inet6() < *rhs.sa_inet6();
- default:
- throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
- }
-@@ -391,6 +406,21 @@ socket_address_inet::set_address_c_str(const char* a) {
- return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
- }
-
-+inline socket_address_inet6
-+socket_address_inet::to_mapped_address() const {
-+ uint32_t addr32[4];
-+ addr32[0] = 0;
-+ addr32[1] = 0;
-+ addr32[2] = htonl(0xffff);
-+ addr32[3] = m_sockaddr.sin_addr.s_addr;
-+
-+ socket_address_inet6 sa;
-+ sa.clear();
-+ sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
-+ sa.set_port_n(m_sockaddr.sin_port);
-+ return sa;
-+}
-+
- inline bool
- socket_address_inet::operator == (const socket_address_inet& rhs) const {
- return
-@@ -406,6 +436,55 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
- m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
- }
-
-+inline std::string
-+socket_address_inet6::address_str() const {
-+ char buf[INET6_ADDRSTRLEN];
-+
-+ if (!address_c_str(buf, INET6_ADDRSTRLEN))
-+ return std::string();
-+
-+ return std::string(buf);
-+}
-+
-+inline bool
-+socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
-+ return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
-+}
-+
-+inline bool
-+socket_address_inet6::set_address_c_str(const char* a) {
-+ return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
-+}
-+
-+inline socket_address
-+socket_address_inet6::normalize_address() const {
-+ const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
-+ if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
-+ socket_address addr4;
-+ addr4.sa_inet()->set_family();
-+ addr4.sa_inet()->set_address_n(addr32[3]);
-+ addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
-+ return addr4;
-+ }
-+ return *reinterpret_cast<const socket_address*>(this);
-+}
-+
-+inline bool
-+socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
-+ return
-+ memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
-+ m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
-+}
-+
-+inline bool
-+socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
-+ int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
-+ return
-+ addr_comp < 0 ||
-+ (addr_comp == 0 ||
-+ m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
-+}
-+
- }
-
- #endif
-diff --git a/src/command_download.cc b/src/command_download.cc
-index 5a1b2ed..3694066 100644
---- a/src/command_download.cc
-+++ b/src/command_download.cc
-@@ -308,7 +308,10 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
- if (download->download()->info()->is_private())
- throw torrent::input_error("Download is private.");
-
-- ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
-+ ret = std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", host, &port, &dummy);
-+
-+ if (ret < 1)
-+ ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
-
- if (ret == 1)
- port = 6881;
-@@ -318,7 +321,7 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
- if (port < 1 || port > 65535)
- throw torrent::input_error("Invalid port number.");
-
-- torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_STREAM, call_add_d_peer_t(download, port));
-+ torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port));
- }
-
- torrent::Object
-diff --git a/src/command_network.cc b/src/command_network.cc
-index 93af73b..dc61997 100644
---- a/src/command_network.cc
-+++ b/src/command_network.cc
-@@ -170,8 +170,9 @@ apply_scgi(const std::string& arg, int type) {
- lt_log_print(torrent::LOG_RPC_EVENTS,
- "The SCGI socket has not been bound to any address and likely poses a security risk.");
-
-- } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) {
-- if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0)
-+ } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
-+ std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
-+ if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0)
- throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");
-
- saPtr = ai->address();
-diff --git a/src/command_peer.cc b/src/command_peer.cc
-index 0cf103b..0b0e7a6 100644
---- a/src/command_peer.cc
-+++ b/src/command_peer.cc
-@@ -69,7 +69,12 @@ retrieve_p_id_html(torrent::Peer* peer) {
-
- torrent::Object
- retrieve_p_address(torrent::Peer* peer) {
-- return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
-+ const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
-+
-+ if (addr->family() == rak::socket_address::af_inet6)
-+ return "[" + addr->address_str() + "]";
-+ else
-+ return addr->address_str();
- }
-
- torrent::Object
-diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc
-index 3179b73..30e461b 100644
---- a/src/core/curl_get.cc
-+++ b/src/core/curl_get.cc
-@@ -91,9 +91,13 @@ CurlGet::start() {
- curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
- curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
- curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
-- curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-+
-+ curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
-+
- curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
-
-+ m_ipv6 = false;
-+
- m_stack->add_get(this);
- }
-
-@@ -111,6 +115,17 @@ CurlGet::close() {
- }
-
- void
-+CurlGet::retry_ipv6() {
-+ CURL* nhandle = curl_easy_duphandle(m_handle);
-+
-+ curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
-+ curl_easy_cleanup(m_handle);
-+
-+ m_handle = nhandle;
-+ m_ipv6 = true;
-+}
-+
-+void
- CurlGet::receive_timeout() {
- return m_stack->transfer_done(m_handle, "Timed out");
- }
-diff --git a/src/core/curl_get.h b/src/core/curl_get.h
-index 88339c8..4ecedb9 100644
---- a/src/core/curl_get.h
-+++ b/src/core/curl_get.h
-@@ -58,6 +58,9 @@ public:
- void start();
- void close();
-
-+ bool is_using_ipv6() { return m_ipv6; }
-+ void retry_ipv6();
-+
- bool is_busy() const { return m_handle; }
- bool is_active() const { return m_active; }
-
-@@ -75,6 +78,7 @@ private:
- void receive_timeout();
-
- bool m_active;
-+ bool m_ipv6;
-
- rak::priority_item m_taskTimeout;
-
-diff --git a/src/core/curl_stack.cc b/src/core/curl_stack.cc
-index e220fcc..05b628e 100644
---- a/src/core/curl_stack.cc
-+++ b/src/core/curl_stack.cc
-@@ -132,8 +132,23 @@ CurlStack::process_done_handle() {
- if (msg->msg != CURLMSG_DONE)
- throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
-
-- transfer_done(msg->easy_handle,
-- msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
-+ if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
-+ iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
-+
-+ if (itr == end())
-+ throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
-+
-+ if (!(*itr)->is_using_ipv6()) {
-+ (*itr)->retry_ipv6();
-+
-+ if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
-+ throw torrent::internal_error("Error calling curl_multi_add_handle.");
-+ }
-+
-+ } else {
-+ transfer_done(msg->easy_handle,
-+ msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
-+ }
-
- return remaining_msgs != 0;
- }
-diff --git a/src/core/manager.cc b/src/core/manager.cc
-index 2c2bd3b..b00fe6d 100644
---- a/src/core/manager.cc
-+++ b/src/core/manager.cc
-@@ -228,7 +228,8 @@ Manager::set_bind_address(const std::string& addr) {
- int err;
- rak::address_info* ai;
-
-- if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0)
-+ if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
-+ (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
- throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + ".");
-
- try {
-@@ -262,7 +263,8 @@ Manager::set_local_address(const std::string& addr) {
- int err;
- rak::address_info* ai;
-
-- if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0)
-+ if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
-+ (err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
- throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + ".");
-
- try {
-diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc
-index db3fbba..aa1701d 100644
---- a/src/display/window_peer_list.cc
-+++ b/src/display/window_peer_list.cc
-@@ -68,7 +68,7 @@ WindowPeerList::redraw() {
- int x = 2;
- int y = 0;
-
-- m_canvas->print(x, y, "IP"); x += 16;
-+ m_canvas->print(x, y, "IP"); x += 25;
- m_canvas->print(x, y, "UP"); x += 7;
- m_canvas->print(x, y, "DOWN"); x += 7;
- m_canvas->print(x, y, "PEER"); x += 7;
-@@ -99,10 +99,16 @@ WindowPeerList::redraw() {
-
- x = 0;
-
-+ std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
-+
-+ if (ip_address.size() >= 24) {
-+ ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
-+ }
-+
- m_canvas->print(x, y, "%c %s",
- range.first == *m_focus ? '*' : ' ',
-- rak::socket_address::cast_from(p->address())->address_str().c_str());
-- x += 18;
-+ ip_address.c_str());
-+ x += 27;
-
- m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7;
- m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7;
-diff --git a/src/main.cc b/src/main.cc
-index 5f4e2c3..99ac1e7 100644
---- a/src/main.cc
-+++ b/src/main.cc
-@@ -273,6 +273,7 @@ main(int argc, char** argv) {
-
- "method.set_key = event.download.resumed, !_timestamp, ((d.timestamp.started.set_if_z, ((system.time)) ))\n"
- "method.set_key = event.download.finished, !_timestamp, ((d.timestamp.finished.set_if_z, ((system.time)) ))\n"
-+ "method.set_key = event.download.hash_done, !_timestamp, {(branch,((d.complete)),((d.timestamp.finished.set_if_z,(system.time))))}\n"
-
- "method.insert.c_simple = group.insert_persistent_view,"
- "((view.add,((argument.0)))),((view.persistent,((argument.0)))),((group.insert,((argument.0)),((argument.0))))\n"
-diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc
-index 338519d..e30594d 100644
---- a/src/utils/socket_fd.cc
-+++ b/src/utils/socket_fd.cc
-@@ -71,7 +71,10 @@ SocketFd::set_priority(priority_type p) {
- check_valid();
- int opt = p;
-
-- return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
-+ if (m_ipv6_socket)
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
-+ else
-+ return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
- }
-
- bool
-@@ -130,12 +133,30 @@ SocketFd::get_error() const {
-
- bool
- SocketFd::open_stream() {
-- return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
-+ m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
-+
-+ if (m_fd == -1) {
-+ m_ipv6_socket = false;
-+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
-+ }
-+
-+ m_ipv6_socket = true;
-+
-+ int zero = 0;
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
- }
-
- bool
- SocketFd::open_datagram() {
-- return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
-+ m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
-+ if (m_fd == -1) {
-+ m_ipv6_socket = false;
-+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
-+ }
-+ m_ipv6_socket = true;
-+
-+ int zero = 0;
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
- }
-
- bool
-@@ -153,6 +174,11 @@ bool
- SocketFd::bind(const rak::socket_address& sa) {
- check_valid();
-
-+ if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
-+ rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
-+ return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
-+ }
-+
- return !::bind(m_fd, sa.c_sockaddr(), sa.length());
- }
-
-@@ -160,6 +186,11 @@ bool
- SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
- check_valid();
-
-+ if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
-+ rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
-+ return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
-+ }
-+
- return !::bind(m_fd, sa.c_sockaddr(), length);
- }
-
-@@ -167,10 +198,31 @@ bool
- SocketFd::connect(const rak::socket_address& sa) {
- check_valid();
-
-+ if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
-+ rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
-+ return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
-+ }
-+
- return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
- }
-
- bool
-+SocketFd::getsockname(rak::socket_address *sa) {
-+ check_valid();
-+
-+ socklen_t len = sizeof(rak::socket_address);
-+ if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
-+ return false;
-+ }
-+
-+ if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
-+ *sa = sa->sa_inet6()->normalize_address();
-+ }
-+
-+ return true;
-+}
-+
-+bool
- SocketFd::listen(int size) {
- check_valid();
-
-@@ -182,7 +234,14 @@ SocketFd::accept(rak::socket_address* sa) {
- check_valid();
- socklen_t len = sizeof(rak::socket_address);
-
-- return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
-+ if (sa == NULL) {
-+ return SocketFd(::accept(m_fd, NULL, &len));
-+ }
-+ int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
-+ if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
-+ *sa = sa->sa_inet6()->normalize_address();
-+ }
-+ return SocketFd(fd);
- }
-
- // unsigned int
-diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h
-index 1376653..6010182 100644
---- a/src/utils/socket_fd.h
-+++ b/src/utils/socket_fd.h
-@@ -80,6 +80,7 @@ public:
- bool bind(const rak::socket_address& sa);
- bool bind(const rak::socket_address& sa, unsigned int length);
- bool connect(const rak::socket_address& sa);
-+ bool getsockname(rak::socket_address* sa);
-
- bool listen(int size);
- SocketFd accept(rak::socket_address* sa);
-@@ -91,6 +92,7 @@ private:
- inline void check_valid() const;
-
- int m_fd;
-+ bool m_ipv6_socket;
- };
-
- }