summaryrefslogtreecommitdiffstats
path: root/rtorrent-extended/ipv6.patch
diff options
context:
space:
mode:
Diffstat (limited to 'rtorrent-extended/ipv6.patch')
-rw-r--r--rtorrent-extended/ipv6.patch572
1 files changed, 572 insertions, 0 deletions
diff --git a/rtorrent-extended/ipv6.patch b/rtorrent-extended/ipv6.patch
new file mode 100644
index 0000000..de72d94
--- /dev/null
+++ b/rtorrent-extended/ipv6.patch
@@ -0,0 +1,572 @@
+diff --git a/rak/socket_address.h b/rak/socket_address.h
+index 25fdb37..d38533e 100644
+--- a/rak/socket_address.h
++++ b/rak/socket_address.h
+@@ -145,7 +145,7 @@ private:
+ };
+ };
+
+-// Remeber to set the AF_INET.
++// Remember to set the AF_INET.
+
+ class socket_address_inet {
+ public:
+@@ -184,6 +184,10 @@ public:
+
+ const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
+ const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
++
++#ifdef RAK_USE_INET6
++ socket_address_inet6 to_mapped_address() const;
++#endif
+
+ bool operator == (const socket_address_inet& rhs) const;
+ bool operator < (const socket_address_inet& rhs) const;
+@@ -192,6 +196,52 @@ private:
+ struct sockaddr_in m_sockaddr;
+ };
+
++#ifdef RAK_USE_INET6
++// Remember to set the AF_INET6.
++
++class socket_address_inet6 {
++public:
++ 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; }
++
++ void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
++
++ 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; }
++
++ in6_addr address() const { return m_sockaddr.sin6_addr; }
++ std::string address_str() const;
++ bool address_c_str(char* buf, socklen_t size) const;
++
++ 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);
++
++ void set_address_any() { set_port(0); set_address(in6addr_any); }
++
++ sa_family_t family() const { return m_sockaddr.sin6_family; }
++ void set_family() { m_sockaddr.sin6_family = AF_INET6; }
++
++ 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:
++ struct sockaddr_in6 m_sockaddr;
++};
++#endif
++
+ // Unique key for the address, excluding port numbers etc.
+ class socket_address_key {
+ public:
+@@ -241,8 +291,10 @@ socket_address::is_valid() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->is_valid();
+-// case af_inet6:
+-// return sa_inet6().is_valid();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->is_valid();
++#endif
+ default:
+ return false;
+ }
+@@ -253,6 +305,10 @@ socket_address::is_bindable() const {
+ switch (family()) {
+ case af_inet:
+ return !sa_inet()->is_address_any();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return !sa_inet6()->is_address_any();
++#endif
+ default:
+ return false;
+ }
+@@ -263,6 +319,10 @@ socket_address::is_address_any() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->is_address_any();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->is_address_any();
++#endif
+ default:
+ return true;
+ }
+@@ -273,6 +333,10 @@ socket_address::port() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->port();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->port();
++#endif
+ default:
+ return 0;
+ }
+@@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->set_port(p);
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->set_port(p);
++#endif
+ default:
+ break;
+ }
+@@ -293,6 +361,10 @@ socket_address::address_str() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->address_str();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->address_str();
++#endif
+ default:
+ return std::string();
+ }
+@@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->address_c_str(buf, size);
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sa_inet6()->address_c_str(buf, size);
++#endif
+ default:
+ return false;
+ }
+@@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) {
+ sa_inet()->set_family();
+ return true;
+
++#ifdef RAK_USE_INET6
++ } else if (sa_inet6()->set_address_c_str(a)) {
++ sa_inet6()->set_family();
++ return true;
++#endif
++
+ } else {
+ return false;
+ }
+@@ -325,6 +407,10 @@ socket_address::length() const {
+ switch(family()) {
+ case af_inet:
+ return sizeof(sockaddr_in);
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return sizeof(sockaddr_in6);
++#endif
+ default:
+ return 0;
+ }
+@@ -349,8 +435,10 @@ 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();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return *sa_inet6() == *rhs.sa_inet6();
++#endif
+ default:
+ throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
+ }
+@@ -364,8 +452,10 @@ 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();
++#ifdef RAK_USE_INET6
++ case af_inet6:
++ return *sa_inet6() < *rhs.sa_inet6();
++#endif
+ default:
+ throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
+ }
+@@ -391,6 +481,23 @@ socket_address_inet::set_address_c_str(const char* a) {
+ return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
+ }
+
++#ifdef RAK_USE_INET6
++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;
++}
++#endif
++
+ inline bool
+ socket_address_inet::operator == (const socket_address_inet& rhs) const {
+ return
+@@ -406,6 +513,59 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
+ m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
+ }
+
++#ifdef RAK_USE_INET6
++
++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
++
+ }
+
+ #endif
+diff --git a/src/command_peer.cc b/src/command_peer.cc
+index 9708a8d..0aae8e0 100644
+--- a/src/command_peer.cc
++++ b/src/command_peer.cc
+@@ -68,7 +68,13 @@ 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());
++#ifdef RAK_USE_INET6
++ if (addr->family() == rak::socket_address::af_inet6)
++ return "[" + addr->address_str() + "]";
++ else
++#endif
++ return addr->address_str();
+ }
+
+ torrent::Object
+diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc
+index f0767b7..4a904e1 100644
+--- a/src/core/curl_get.cc
++++ b/src/core/curl_get.cc
+@@ -88,8 +88,20 @@ 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);
++
++ // Even when IPv6-enabled, we don't want to use CURL_IPRESOLVE_WHATEVER,
++ // since that will usually prefer connecting over IPv6 to the tracker.
++ // Since it's usually a lot easier to find our global IPv6 address
++ // (if we have one) than our global IPv4 address, we prefer connecting
++ // over IPv4 if we can, so that the tracker will get our IPv4 address
++ // that way. If the resolve fails, CurlStack will call retry_ipv6()
++ // on us and we'll make a second attempt with CURL_IPRESOLVE_V6.
+ curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
++
+ curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
++#ifdef RAK_USE_INET6
++ m_ipv6 = false;
++#endif
+
+ m_stack->add_get(this);
+ }
+@@ -107,6 +119,17 @@ CurlGet::close() {
+ m_handle = NULL;
+ }
+
++#ifdef RAK_USE_INET6
++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;
++}
++#endif
++
+ 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 1d3a0d5..2b7836b 100644
+--- a/src/core/curl_get.h
++++ b/src/core/curl_get.h
+@@ -56,6 +56,10 @@ public:
+
+ void start();
+ void close();
++#ifdef RAK_USE_INET6
++ bool is_using_ipv6() { return m_ipv6; }
++ void retry_ipv6();
++#endif
+
+ bool is_busy() const { return m_handle; }
+ bool is_active() const { return m_active; }
+@@ -74,6 +78,9 @@ private:
+ void receive_timeout();
+
+ bool m_active;
++#ifdef RAK_USE_INET6
++ bool m_ipv6;
++#endif
+
+ rak::priority_item m_taskTimeout;
+
+diff --git a/src/core/curl_stack.cc b/src/core/curl_stack.cc
+index 3adfab5..915b11a 100644
+--- a/src/core/curl_stack.cc
++++ b/src/core/curl_stack.cc
+@@ -111,6 +111,21 @@ CurlStack::receive_action(CurlSocket* socket, int events) {
+ if (msg->msg != CURLMSG_DONE)
+ throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
+
++#ifdef RAK_USE_INET6
++ 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.");
++ continue;
++ }
++ } else
++#endif
+ transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
+ }
+
+diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc
+index 628b74b..63a22ef 100644
+--- a/src/display/window_peer_list.cc
++++ b/src/display/window_peer_list.cc
+@@ -68,7 +68,11 @@ WindowPeerList::redraw() {
+ int x = 2;
+ int y = 0;
+
+- m_canvas->print(x, y, "IP"); x += 16;
++#ifdef RAK_USE_INET6
++ m_canvas->print(x, y, "IP"); x += 25;
++#else
++ m_canvas->print(x, y, "IP"); x += 16;
++#endif
+ 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 +103,21 @@ WindowPeerList::redraw() {
+
+ x = 0;
+
++ std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
++#ifdef RAK_USE_INET6
++ if (ip_address.size() >= 24) {
++ ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
++ }
++#endif
++
+ m_canvas->print(x, y, "%c %s",
+ range.first == *m_focus ? '*' : ' ',
+- rak::socket_address::cast_from(p->address())->address_str().c_str());
++ ip_address.c_str());
++#ifdef RAK_USE_INET6
++ x += 27;
++#else
+ x += 18;
++#endif
+
+ 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/utils/socket_fd.cc b/src/utils/socket_fd.cc
+index 414d4f7..2545304 100644
+--- a/src/utils/socket_fd.cc
++++ b/src/utils/socket_fd.cc
+@@ -71,6 +71,11 @@ SocketFd::set_priority(priority_type p) {
+ check_valid();
+ int opt = p;
+
++#ifdef RAK_USE_INET6
++ if (m_ipv6_socket)
++ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
++ else
++#endif
+ return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
+ }
+
+@@ -130,12 +135,36 @@ SocketFd::get_error() const {
+
+ bool
+ SocketFd::open_stream() {
++#ifdef RAK_USE_INET6
++ 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;
++#else
+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
++#endif
+ }
+
+ bool
+ SocketFd::open_datagram() {
++#ifdef RAK_USE_INET6
++ 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;
++#else
+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
++#endif
+ }
+
+ bool
+@@ -167,10 +196,34 @@ bool
+ SocketFd::connect(const rak::socket_address& sa) {
+ check_valid();
+
++#ifdef RAK_USE_INET6
++ 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;
++ }
++#endif
+ 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;
++ }
++
++#ifdef RAK_USE_INET6
++ if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
++ *sa = sa->sa_inet6()->normalize_address();
++ }
++#endif
++
++ return true;
++}
++
++bool
+ SocketFd::listen(int size) {
+ check_valid();
+
+@@ -182,7 +235,18 @@ SocketFd::accept(rak::socket_address* sa) {
+ check_valid();
+ socklen_t len = sizeof(rak::socket_address);
+
++#ifdef RAK_USE_INET6
++ 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);
++#else
+ return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
++#endif
+ }
+
+ // unsigned int
+diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h
+index 7898712..35d2eda 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,9 @@ private:
+ inline void check_valid() const;
+
+ int m_fd;
++#ifdef RAK_USE_INET6
++ bool m_ipv6_socket;
++#endif
+ };
+
+ }