From 5770f616594045ad20f456633a875f0c04e8e0f1 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 14 Aug 2014 21:01:17 +0900 Subject: [PATCH 01/16] Applied ipv6 patch. --- rak/socket_address.h | 174 +++++++++++++++- src/dht/dht_node.cc | 23 +- src/dht/dht_server.cc | 10 + src/net/Makefile.am | 2 + src/net/address_list.cc | 12 ++ src/net/address_list.h | 25 +++ src/net/local_addr.cc | 336 ++++++++++++++++++++++++++++++ src/net/local_addr.h | 64 ++++++ src/net/socket_datagram.cc | 8 +- src/net/socket_fd.cc | 76 +++++++ src/net/socket_fd.h | 4 + src/torrent/connection_manager.cc | 15 +- src/torrent/event.h | 4 + src/torrent/peer/peer_list.cc | 14 +- src/tracker/tracker_http.cc | 46 +++- src/tracker/tracker_udp.cc | 11 +- 16 files changed, 793 insertions(+), 31 deletions(-) create mode 100644 src/net/local_addr.cc create mode 100644 src/net/local_addr.h diff --git a/rak/socket_address.h b/rak/socket_address.h index 25fdb37f9..d38533e55 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -145,7 +145,7 @@ class socket_address { }; }; -// Remeber to set the AF_INET. +// Remember to set the AF_INET. class socket_address_inet { public: @@ -184,6 +184,10 @@ class socket_address_inet { const sockaddr* c_sockaddr() const { return reinterpret_cast(&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 @@ class socket_address_inet { 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(&m_sockaddr); } + sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; } + + const sockaddr* c_sockaddr() const { return reinterpret_cast(&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(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(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(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/dht/dht_node.cc b/src/dht/dht_node.cc index 69b16db0f..19afb1aa6 100644 --- a/src/dht/dht_node.cc +++ b/src/dht/dht_node.cc @@ -54,8 +54,15 @@ DhtNode::DhtNode(const HashString& id, const rak::socket_address* sa) : m_recentlyInactive(0), m_bucket(NULL) { +#ifdef RAK_USE_INET6 + if (sa->family() != rak::socket_address::af_inet && + (sa->family() != rak::socket_address::af_inet6 || + !sa->sa_inet6()->is_any())) + throw resource_error("Addres not af_inet or in6addr_any"); +#else if (sa->family() != rak::socket_address::af_inet) throw resource_error("Address not af_inet"); +#endif } DhtNode::DhtNode(const std::string& id, const Object& cache) : @@ -84,8 +91,20 @@ DhtNode::store_compact(char* buffer) const { Object* DhtNode::store_cache(Object* container) const { - container->insert_key("i", m_socketAddress.sa_inet()->address_h()); - container->insert_key("p", m_socketAddress.sa_inet()->port()); +#ifdef RAK_USE_INET6 + if (m_socketAddress.family() == rak::socket_address::af_inet6) { + // Currently, all we support is in6addr_any (checked in the constructor), + // which is effectively equivalent to this. Note that we need to specify + // int64_t explicitly here because a zero constant is special in C++ and + // thus we need an explicit match. + container->insert_key("i", int64_t(0)); + container->insert_key("p", m_socketAddress.sa_inet6()->port()); + } else +#endif + { + container->insert_key("i", m_socketAddress.sa_inet()->address_h()); + container->insert_key("p", m_socketAddress.sa_inet()->port()); + } container->insert_key("t", m_lastSeen); return container; } diff --git a/src/dht/dht_server.cc b/src/dht/dht_server.cc index 844d5f786..9d2e014da 100644 --- a/src/dht/dht_server.cc +++ b/src/dht/dht_server.cc @@ -701,6 +701,16 @@ DhtServer::event_read() { if (read < 0) break; +#ifdef RAK_USE_INET6 + // We can currently only process mapped-IPv4 addresses, not real IPv6. + // Translate them to an af_inet socket_address. + if (sa.family() == rak::socket_address::af_inet6) + sa = sa.sa_inet6()->normalize_address(); +#endif + + if (sa.family() != rak::socket_address::af_inet) + continue; + total += read; // If it's not a valid bencode dictionary at all, it's probably not a DHT diff --git a/src/net/Makefile.am b/src/net/Makefile.am index 4e6446c9e..fb4da4f3b 100644 --- a/src/net/Makefile.am +++ b/src/net/Makefile.am @@ -4,6 +4,8 @@ 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 \ diff --git a/src/net/address_list.cc b/src/net/address_list.cc index 295214978..ea0f4891d 100644 --- a/src/net/address_list.cc +++ b/src/net/address_list.cc @@ -77,6 +77,18 @@ AddressList::parse_address_compact(raw_string s) { std::back_inserter(*this)); } +#ifdef RAK_USE_INET6 +void +AddressList::parse_address_compact_ipv6(const std::string& s) { + if (sizeof(const SocketAddressCompact6) != 18) + throw internal_error("ConnectionList::AddressList::parse_address_compact_ipv6(...) bad struct size."); + + std::copy(reinterpret_cast(s.c_str()), + reinterpret_cast(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact6)), + std::back_inserter(*this)); +} +#endif + void AddressList::parse_address_bencode(raw_list s) { if (sizeof(const SocketAddressCompact) != 6) diff --git a/src/net/address_list.h b/src/net/address_list.h index c884da3d6..07db551ae 100644 --- a/src/net/address_list.h +++ b/src/net/address_list.h @@ -54,6 +54,9 @@ class AddressList : public std::list { void parse_address_compact(raw_string s); void parse_address_compact(const std::string& s); +#ifdef RAK_USE_INET6 + void parse_address_compact_ipv6(const std::string& s); +#endif private: static rak::socket_address parse_address(const Object& b); @@ -99,6 +102,28 @@ struct SocketAddressCompact { const char* c_str() const { return reinterpret_cast(this); } } __attribute__ ((packed)); +#ifdef RAK_USE_INET6 +struct SocketAddressCompact6 { + SocketAddressCompact6() {} + SocketAddressCompact6(in6_addr a, uint16_t p) : addr(a), port(p) {} + SocketAddressCompact6(const rak::socket_address_inet6* sa) : addr(sa->address()), port(sa->port_n()) {} + + operator rak::socket_address () const { + rak::socket_address sa; + sa.sa_inet6()->clear(); + sa.sa_inet6()->set_port_n(port); + sa.sa_inet6()->set_address(addr); + + return sa; + } + + in6_addr addr; + uint16_t port; + + const char* c_str() const { return reinterpret_cast(this); } +} __attribute__ ((packed)); +#endif + } #endif diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc new file mode 100644 index 000000000..fae3f85ce --- /dev/null +++ b/src/net/local_addr.cc @@ -0,0 +1,336 @@ +// 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#endif + +#include "torrent/exceptions.h" +#include "socket_fd.h" +#include "local_addr.h" + +namespace torrent { +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/16, 192.168.0.0/24) +// 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(0)) { + return 4; + } + if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) { + return 3; + } + if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x0a000000U) || + (addr.s_addr & htonl(0xffff0000U)) == htonl(0xac100000U) || + (addr.s_addr & htonl(0xffff0000U)) == htonl(0xc0a80000U)) { + return 2; + } + return 1; +} + +#ifdef RAK_USE_INET6 +// 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(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; +} +#endif + +int get_priority(const rak::socket_address& addr) { + switch (addr.family()) { + case AF_INET: + return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr); +#ifdef RAK_USE_INET6 + case AF_INET6: + return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr); +#endif + default: + throw torrent::internal_error("Unknown address family given to compare"); + } +} + +} + +#ifdef __linux__ + +// 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) { + ifaddrs *ifaddrs; + if (getifaddrs(&ifaddrs)) { + return false; + } + + rak::socket_address best_addr; + switch (family) { + case AF_INET: + best_addr.sa_inet()->clear(); + break; +#ifdef RAK_USE_INET6 + case AF_INET6: + best_addr.sa_inet6()->clear(); + break; +#endif + 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; +#ifdef RAK_USE_INET6 + case AF_INET6: + this_addr.sa_inet6()->clear(); + this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta)); + break; +#endif + } + } + 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; +#ifdef RAK_USE_INET6 + case rak::socket_address::af_inet6: + dummy_dest.set_address_c_str("2001:700::"); + break; +#endif + 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 new file mode 100644 index 000000000..43bc82066 --- /dev/null +++ b/src/net/local_addr.h @@ -0,0 +1,64 @@ +// 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 +// +// 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 + +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/net/socket_datagram.cc b/src/net/socket_datagram.cc index 57fbb1fb9..c19524565 100644 --- a/src/net/socket_datagram.cc +++ b/src/net/socket_datagram.cc @@ -73,7 +73,13 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc int r; if (sa != NULL) { - r = ::sendto(m_fileDesc, buffer, length, 0, sa->sa_inet()->c_sockaddr(), sizeof(rak::socket_address_inet)); +#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(); + r = ::sendto(m_fileDesc, buffer, length, 0, sa_mapped.c_sockaddr(), sizeof(rak::socket_address_inet6)); + } else +#endif + r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()); } else { r = ::send(m_fileDesc, buffer, length, 0); } diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc index 8c6a4778b..314255794 100644 --- a/src/net/socket_fd.cc +++ b/src/net/socket_fd.cc @@ -70,6 +70,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; } @@ -112,12 +117,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 @@ -148,6 +177,12 @@ bool SocketFd::bind(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 !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); + } +#endif return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } @@ -155,6 +190,12 @@ bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { 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 !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); + } +#endif return !::bind(m_fd, sa.c_sockaddr(), length); } @@ -162,9 +203,33 @@ 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(); @@ -177,7 +242,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/net/socket_fd.h b/src/net/socket_fd.h index 3435eadac..3ad5fe0b5 100644 --- a/src/net/socket_fd.h +++ b/src/net/socket_fd.h @@ -79,6 +79,7 @@ class SocketFd { 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); @@ -90,6 +91,9 @@ class SocketFd { inline void check_valid() const; int m_fd; +#ifdef RAK_USE_INET6 + bool m_ipv6_socket; +#endif }; } diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc index 33ae1d902..b9aa3bc6d 100644 --- a/src/torrent/connection_manager.cc +++ b/src/torrent/connection_manager.cc @@ -92,13 +92,12 @@ ConnectionManager::ConnectionManager() : m_listen_backlog(SOMAXCONN) { m_bindAddress = (new rak::socket_address())->c_sockaddr(); - rak::socket_address::cast_from(m_bindAddress)->sa_inet()->clear(); - m_localAddress = (new rak::socket_address())->c_sockaddr(); - rak::socket_address::cast_from(m_localAddress)->sa_inet()->clear(); - m_proxyAddress = (new rak::socket_address())->c_sockaddr(); - rak::socket_address::cast_from(m_proxyAddress)->sa_inet()->clear(); + + rak::socket_address::cast_from(m_bindAddress)->clear(); + rak::socket_address::cast_from(m_localAddress)->clear(); + rak::socket_address::cast_from(m_proxyAddress)->clear(); m_slot_resolver = std::bind(&resolve_host, std::placeholders::_1, @@ -143,8 +142,10 @@ void ConnectionManager::set_bind_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); +#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a bind address that is not an af_inet address."); +#endif rak::socket_address::cast_from(m_bindAddress)->copy(*rsa, rsa->length()); } @@ -153,8 +154,10 @@ void ConnectionManager::set_local_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); +#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a local address that is not an af_inet address."); +#endif rak::socket_address::cast_from(m_localAddress)->copy(*rsa, rsa->length()); } @@ -163,8 +166,10 @@ void ConnectionManager::set_proxy_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); +#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a proxy address that is not an af_inet address."); +#endif rak::socket_address::cast_from(m_proxyAddress)->copy(*rsa, rsa->length()); } diff --git a/src/torrent/event.h b/src/torrent/event.h index c33694777..0923813a2 100644 --- a/src/torrent/event.h +++ b/src/torrent/event.h @@ -60,6 +60,10 @@ class LIBTORRENT_EXPORT Event { protected: int m_fileDesc; + +#ifdef RAK_USE_INET6 + bool m_ipv6_socket; +#endif }; } diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc index be5540052..03bf0908a 100644 --- a/src/torrent/peer/peer_list.cc +++ b/src/torrent/peer/peer_list.cc @@ -75,15 +75,23 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) { // humans. return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h(); +#ifdef RAK_USE_INET6 + else { + const in6_addr addr1 = sa1->sa_inet6()->address(); + const in6_addr addr2 = sa2->sa_inet6()->address(); + return memcmp(&addr1, &addr2, sizeof(in6_addr)) < 0; + } +#else else - // When we implement INET6 handling, embed the ipv4 address in - // the ipv6 address. throw internal_error("socket_address_key(...) tried to compare an invalid family type."); +#endif + } inline bool socket_address_key::is_comparable(const sockaddr* sa) { - return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet; + return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet || + rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6; } struct peer_list_equal_port : public std::binary_function { diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc index 6dbd0f542..cbc51005b 100644 --- a/src/tracker/tracker_http.cc +++ b/src/tracker/tracker_http.cc @@ -44,6 +44,7 @@ #include #include "net/address_list.h" +#include "net/local_addr.h" #include "torrent/connection_manager.h" #include "torrent/download_info.h" #include "torrent/exceptions.h" @@ -141,9 +142,16 @@ TrackerHttp::send_state(int state) { const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address()); - if (localAddress->family() == rak::socket_address::af_inet && - !localAddress->sa_inet()->is_address_any()) + if (!localAddress->is_address_any()) s << "&ip=" << localAddress->address_str(); + +#ifdef RAK_USE_INET6 + if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet6) { + 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()); + } +#endif if (info->is_compact()) s << "&compact=1"; @@ -332,18 +340,34 @@ TrackerHttp::process_success(const Object& object) { AddressList l; - try { - // Due to some trackers sending the wrong type when no peers are - // available, don't bork on it. - if (object.get_key("peers").is_string()) - l.parse_address_compact(object.get_key_string("peers")); + if (!object.has_key("peers") +#ifdef RAK_USE_INET6 + && !object.has_key("peers6") +#endif + ) { + return receive_failed("No peers returned"); + } + + if (object.has_key("peers")) { + try { + // Due to some trackers sending the wrong type when no peers are + // available, don't bork on it. + if (object.get_key("peers").is_string()) + l.parse_address_compact(object.get_key_string("peers")); + + else if (object.get_key("peers").is_list()) + l.parse_address_normal(object.get_key_list("peers")); - else if (object.get_key("peers").is_list()) - l.parse_address_normal(object.get_key_list("peers")); + } catch (bencode_error& e) { + return receive_failed(e.what()); + } + } - } catch (bencode_error& e) { - return receive_failed(e.what()); +#ifdef RAK_USE_INET6 + if (object.has_key("peers6")) { + l.parse_address_compact_ipv6(object.get_key_string("peers6")); } +#endif close_directly(); m_parent->receive_success(this, &l); diff --git a/src/tracker/tracker_udp.cc b/src/tracker/tracker_udp.cc index fc76c14c8..3bd5fc47c 100644 --- a/src/tracker/tracker_udp.cc +++ b/src/tracker/tracker_udp.cc @@ -337,11 +337,18 @@ TrackerUdp::prepare_announce_input() { const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address()); - // This code assumes we're have a inet address. +#ifdef RAK_USE_INET6 + uint32_t local_addr = 0; + if (localAddress->family() == rak::socket_address::af_inet) + local_addr = localAddress->sa_inet()->address_n(); +#else if (localAddress->family() != rak::socket_address::af_inet) throw internal_error("TrackerUdp::prepare_announce_input() info->local_address() not of family AF_INET."); + + uint32_t local_addr = localAddress->sa_inet()->address_n(); +#endif - m_writeBuffer->write_32_n(localAddress->sa_inet()->address_n()); + m_writeBuffer->write_32_n(local_addr); m_writeBuffer->write_32(m_parent->key()); m_writeBuffer->write_32(m_parent->numwant()); m_writeBuffer->write_16(manager->connection_manager()->listen_port()); From e14dd067efe9f29cf11f8e72e69c74e30c4adca1 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 19 Aug 2014 23:52:52 +0900 Subject: [PATCH 02/16] Removed ifdef for ipv6. --- configure.ac | 1 - rak/socket_address.h | 40 ------------------------------- scripts/common.m4 | 11 --------- src/dht/dht_node.cc | 15 ++++-------- src/dht/dht_server.cc | 2 -- src/net/address_list.cc | 2 -- src/net/address_list.h | 4 ---- src/net/local_addr.cc | 29 ++++++++++------------ src/net/socket_datagram.cc | 7 +++--- src/net/socket_fd.cc | 34 +++++++++----------------- src/net/socket_fd.h | 2 -- src/torrent/connection_manager.cc | 6 ----- src/torrent/event.h | 3 --- src/torrent/peer/peer_list.cc | 16 ++++++------- src/tracker/tracker_http.cc | 14 ++--------- src/tracker/tracker_udp.cc | 8 +------ 16 files changed, 41 insertions(+), 153 deletions(-) diff --git a/configure.ac b/configure.ac index ffb4f05ab..05d56db97 100644 --- a/configure.ac +++ b/configure.ac @@ -105,7 +105,6 @@ TORRENT_CHECK_EXECINFO() TORRENT_CHECK_PTHREAD_SETNAME_NP() TORRENT_MINCORE() -TORRENT_DISABLE_IPV6 TORRENT_DISABLE_INSTRUMENTATION LIBTORRENT_LIBS="-ltorrent" diff --git a/rak/socket_address.h b/rak/socket_address.h index d38533e55..5f04785d1 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -109,13 +109,11 @@ class socket_address { 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(this); } const socket_address_inet6* sa_inet6() const { return reinterpret_cast(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,9 +137,7 @@ class socket_address { union { sockaddr m_sockaddr; sockaddr_in m_sockaddrInet; -#ifdef RAK_USE_INET6 sockaddr_in6 m_sockaddrInet6; -#endif }; }; @@ -185,9 +181,7 @@ class socket_address_inet { const sockaddr* c_sockaddr() const { return reinterpret_cast(&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; @@ -196,9 +190,6 @@ class socket_address_inet { 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(); } @@ -240,7 +231,6 @@ class socket_address_inet6 { private: struct sockaddr_in6 m_sockaddr; }; -#endif // Unique key for the address, excluding port numbers etc. class socket_address_key { @@ -280,9 +270,7 @@ class socket_address_key { private: union { in_addr m_addr; -// #ifdef RAK_USE_INET6 // in_addr6 m_addr6; -// #endif }; }; @@ -291,10 +279,8 @@ socket_address::is_valid() const { switch (family()) { case af_inet: return sa_inet()->is_valid(); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->is_valid(); -#endif default: return false; } @@ -305,10 +291,8 @@ 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; } @@ -319,10 +303,8 @@ 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; } @@ -333,10 +315,8 @@ 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; } @@ -347,10 +327,8 @@ 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; } @@ -361,10 +339,8 @@ 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(); } @@ -375,10 +351,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); -#ifdef RAK_USE_INET6 case af_inet6: return sa_inet6()->address_c_str(buf, size); -#endif default: return false; } @@ -390,11 +364,9 @@ 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; @@ -407,10 +379,8 @@ 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; } @@ -435,10 +405,8 @@ socket_address::operator == (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() == *rhs.sa_inet(); -#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."); } @@ -452,10 +420,8 @@ socket_address::operator < (const socket_address& rhs) const { switch (family()) { case af_inet: return *sa_inet() < *rhs.sa_inet(); -#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."); } @@ -481,7 +447,6 @@ 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]; @@ -496,7 +461,6 @@ socket_address_inet::to_mapped_address() const { sa.set_port_n(m_sockaddr.sin_port); return sa; } -#endif inline bool socket_address_inet::operator == (const socket_address_inet& rhs) const { @@ -513,8 +477,6 @@ 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]; @@ -564,8 +526,6 @@ socket_address_inet6::operator < (const socket_address_inet6& rhs) const { m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port); } -#endif - } #endif diff --git a/scripts/common.m4 b/scripts/common.m4 index 9885b037f..ff0239280 100644 --- a/scripts/common.m4 +++ b/scripts/common.m4 @@ -229,14 +229,3 @@ AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [ ] ) ]) - - -AC_DEFUN([TORRENT_DISABLE_IPV6], [ - AC_ARG_ENABLE(ipv6, - AC_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/src/dht/dht_node.cc b/src/dht/dht_node.cc index 19afb1aa6..830b0c92e 100644 --- a/src/dht/dht_node.cc +++ b/src/dht/dht_node.cc @@ -54,15 +54,9 @@ DhtNode::DhtNode(const HashString& id, const rak::socket_address* sa) : m_recentlyInactive(0), m_bucket(NULL) { -#ifdef RAK_USE_INET6 if (sa->family() != rak::socket_address::af_inet && - (sa->family() != rak::socket_address::af_inet6 || - !sa->sa_inet6()->is_any())) + (sa->family() != rak::socket_address::af_inet6 || !sa->sa_inet6()->is_any())) throw resource_error("Addres not af_inet or in6addr_any"); -#else - if (sa->family() != rak::socket_address::af_inet) - throw resource_error("Address not af_inet"); -#endif } DhtNode::DhtNode(const std::string& id, const Object& cache) : @@ -91,7 +85,6 @@ DhtNode::store_compact(char* buffer) const { Object* DhtNode::store_cache(Object* container) const { -#ifdef RAK_USE_INET6 if (m_socketAddress.family() == rak::socket_address::af_inet6) { // Currently, all we support is in6addr_any (checked in the constructor), // which is effectively equivalent to this. Note that we need to specify @@ -99,12 +92,12 @@ DhtNode::store_cache(Object* container) const { // thus we need an explicit match. container->insert_key("i", int64_t(0)); container->insert_key("p", m_socketAddress.sa_inet6()->port()); - } else -#endif - { + + } else { container->insert_key("i", m_socketAddress.sa_inet()->address_h()); container->insert_key("p", m_socketAddress.sa_inet()->port()); } + container->insert_key("t", m_lastSeen); return container; } diff --git a/src/dht/dht_server.cc b/src/dht/dht_server.cc index 9d2e014da..1a00908a9 100644 --- a/src/dht/dht_server.cc +++ b/src/dht/dht_server.cc @@ -701,12 +701,10 @@ DhtServer::event_read() { if (read < 0) break; -#ifdef RAK_USE_INET6 // We can currently only process mapped-IPv4 addresses, not real IPv6. // Translate them to an af_inet socket_address. if (sa.family() == rak::socket_address::af_inet6) sa = sa.sa_inet6()->normalize_address(); -#endif if (sa.family() != rak::socket_address::af_inet) continue; diff --git a/src/net/address_list.cc b/src/net/address_list.cc index ea0f4891d..66b97c16c 100644 --- a/src/net/address_list.cc +++ b/src/net/address_list.cc @@ -77,7 +77,6 @@ AddressList::parse_address_compact(raw_string s) { std::back_inserter(*this)); } -#ifdef RAK_USE_INET6 void AddressList::parse_address_compact_ipv6(const std::string& s) { if (sizeof(const SocketAddressCompact6) != 18) @@ -87,7 +86,6 @@ AddressList::parse_address_compact_ipv6(const std::string& s) { reinterpret_cast(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact6)), std::back_inserter(*this)); } -#endif void AddressList::parse_address_bencode(raw_list s) { diff --git a/src/net/address_list.h b/src/net/address_list.h index 07db551ae..d40efd930 100644 --- a/src/net/address_list.h +++ b/src/net/address_list.h @@ -54,9 +54,7 @@ class AddressList : public std::list { void parse_address_compact(raw_string s); void parse_address_compact(const std::string& s); -#ifdef RAK_USE_INET6 void parse_address_compact_ipv6(const std::string& s); -#endif private: static rak::socket_address parse_address(const Object& b); @@ -102,7 +100,6 @@ struct SocketAddressCompact { const char* c_str() const { return reinterpret_cast(this); } } __attribute__ ((packed)); -#ifdef RAK_USE_INET6 struct SocketAddressCompact6 { SocketAddressCompact6() {} SocketAddressCompact6(in6_addr a, uint16_t p) : addr(a), port(p) {} @@ -122,7 +119,6 @@ struct SocketAddressCompact6 { const char* c_str() const { return reinterpret_cast(this); } } __attribute__ ((packed)); -#endif } diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc index fae3f85ce..db40a84f1 100644 --- a/src/net/local_addr.cc +++ b/src/net/local_addr.cc @@ -52,6 +52,9 @@ #include "local_addr.h" namespace torrent { + +#ifdef __linux__ + namespace { // IPv4 priority, from highest to lowest: @@ -61,7 +64,8 @@ namespace { // 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) { +int +get_priority_ipv4(const in_addr& addr) { if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x7f000000U)) { return 5; } @@ -79,7 +83,6 @@ int get_priority_ipv4(const in_addr& addr) { return 1; } -#ifdef RAK_USE_INET6 // IPv6 priority, from highest to lowest: // // 1. Global address (2000::/16 not in 6to4 or Teredo) @@ -87,7 +90,8 @@ int get_priority_ipv4(const in_addr& addr) { // 3. Teredo (2001::/32) // 4. Empty/INADDR_ANY (::) // 5. Everything else (link-local, ULA, etc.) -int get_priority_ipv6(const in6_addr& addr) { +int +get_priority_ipv6(const in6_addr& addr) { const uint32_t *addr32 = reinterpret_cast(addr.s6_addr); if (addr32[0] == htonl(0) && addr32[1] == htonl(0) && @@ -106,16 +110,14 @@ int get_priority_ipv6(const in6_addr& addr) { } return 5; } -#endif -int get_priority(const rak::socket_address& addr) { +int +get_priority(const rak::socket_address& addr) { switch (addr.family()) { case AF_INET: return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr); -#ifdef RAK_USE_INET6 case AF_INET6: return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr); -#endif default: throw torrent::internal_error("Unknown address family given to compare"); } @@ -123,8 +125,6 @@ int get_priority(const rak::socket_address& addr) { } -#ifdef __linux__ - // 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) { @@ -138,11 +138,9 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) { case AF_INET: best_addr.sa_inet()->clear(); break; -#ifdef RAK_USE_INET6 case AF_INET6: best_addr.sa_inet6()->clear(); break; -#endif default: throw torrent::internal_error("Unknown address family given to get_local_address"); } @@ -263,12 +261,10 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) { this_addr.sa_inet()->clear(); this_addr.sa_inet()->set_address(*(const in_addr *)RTA_DATA(rta)); break; -#ifdef RAK_USE_INET6 case AF_INET6: this_addr.sa_inet6()->clear(); this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta)); break; -#endif } } if (!seen_addr) @@ -298,7 +294,8 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) { #else // Generic POSIX variant. -bool get_local_address(sa_family_t family, rak::socket_address *address) { +bool +get_local_address(sa_family_t family, rak::socket_address *address) { SocketFd sock; if (!sock.open_datagram()) { return false; @@ -311,14 +308,13 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) { case rak::socket_address::af_inet: dummy_dest.set_address_c_str("4.0.0.0"); break; -#ifdef RAK_USE_INET6 case rak::socket_address::af_inet6: dummy_dest.set_address_c_str("2001:700::"); break; -#endif default: throw internal_error("Unknown address family"); } + dummy_dest.set_port(80); if (!sock.connect(dummy_dest)) { @@ -328,6 +324,7 @@ bool get_local_address(sa_family_t family, rak::socket_address *address) { bool ret = sock.getsockname(address); sock.close(); + return ret; } diff --git a/src/net/socket_datagram.cc b/src/net/socket_datagram.cc index c19524565..e7c5e1a55 100644 --- a/src/net/socket_datagram.cc +++ b/src/net/socket_datagram.cc @@ -73,13 +73,12 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc int r; if (sa != NULL) { -#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(); r = ::sendto(m_fileDesc, buffer, length, 0, sa_mapped.c_sockaddr(), sizeof(rak::socket_address_inet6)); - } else -#endif - r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()); + } else { + r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()); + } } else { r = ::send(m_fileDesc, buffer, length, 0); } diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc index 314255794..6238fcf93 100644 --- a/src/net/socket_fd.cc +++ b/src/net/socket_fd.cc @@ -70,12 +70,10 @@ 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; + return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0; } bool @@ -117,36 +115,32 @@ 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 @@ -177,12 +171,11 @@ bool SocketFd::bind(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 !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); } -#endif + return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } @@ -190,12 +183,11 @@ bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { 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 !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)); } -#endif + return !::bind(m_fd, sa.c_sockaddr(), length); } @@ -203,12 +195,11 @@ 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; } @@ -221,11 +212,9 @@ SocketFd::getsockname(rak::socket_address *sa) { 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; } @@ -242,18 +231,17 @@ 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/net/socket_fd.h b/src/net/socket_fd.h index 3ad5fe0b5..bcb302d6c 100644 --- a/src/net/socket_fd.h +++ b/src/net/socket_fd.h @@ -91,9 +91,7 @@ class SocketFd { inline void check_valid() const; int m_fd; -#ifdef RAK_USE_INET6 bool m_ipv6_socket; -#endif }; } diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc index b9aa3bc6d..972dcbfc3 100644 --- a/src/torrent/connection_manager.cc +++ b/src/torrent/connection_manager.cc @@ -142,10 +142,8 @@ void ConnectionManager::set_bind_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); -#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a bind address that is not an af_inet address."); -#endif rak::socket_address::cast_from(m_bindAddress)->copy(*rsa, rsa->length()); } @@ -154,10 +152,8 @@ void ConnectionManager::set_local_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); -#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a local address that is not an af_inet address."); -#endif rak::socket_address::cast_from(m_localAddress)->copy(*rsa, rsa->length()); } @@ -166,10 +162,8 @@ void ConnectionManager::set_proxy_address(const sockaddr* sa) { const rak::socket_address* rsa = rak::socket_address::cast_from(sa); -#ifndef RAK_USE_INET6 if (rsa->family() != rak::socket_address::af_inet) throw input_error("Tried to set a proxy address that is not an af_inet address."); -#endif rak::socket_address::cast_from(m_proxyAddress)->copy(*rsa, rsa->length()); } diff --git a/src/torrent/event.h b/src/torrent/event.h index 0923813a2..f3549762f 100644 --- a/src/torrent/event.h +++ b/src/torrent/event.h @@ -60,10 +60,7 @@ class LIBTORRENT_EXPORT Event { protected: int m_fileDesc; - -#ifdef RAK_USE_INET6 bool m_ipv6_socket; -#endif }; } diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc index 03bf0908a..f2c08c4d2 100644 --- a/src/torrent/peer/peer_list.cc +++ b/src/torrent/peer/peer_list.cc @@ -67,25 +67,23 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) { const rak::socket_address* sa1 = rak::socket_address::cast_from(s1); const rak::socket_address* sa2 = rak::socket_address::cast_from(s2); - if (sa1->family() != sa2->family()) + if (sa1->family() != sa2->family()) { return sa1->family() < sa2->family(); - else if (sa1->family() == rak::socket_address::af_inet) + } else if (sa1->family() == rak::socket_address::af_inet) { // Sort by hardware byte order to ensure proper ordering for // humans. return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h(); -#ifdef RAK_USE_INET6 - else { + } else if (sa1->family() == rak::socket_address::af_inet6) { const in6_addr addr1 = sa1->sa_inet6()->address(); const in6_addr addr2 = sa2->sa_inet6()->address(); + return memcmp(&addr1, &addr2, sizeof(in6_addr)) < 0; - } -#else - else - throw internal_error("socket_address_key(...) tried to compare an invalid family type."); -#endif + } else { + throw internal_error("socket_address_key(...) tried to compare an invalid family type."); + } } inline bool diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc index cbc51005b..0bf0f36ff 100644 --- a/src/tracker/tracker_http.cc +++ b/src/tracker/tracker_http.cc @@ -145,13 +145,11 @@ TrackerHttp::send_state(int state) { if (!localAddress->is_address_any()) s << "&ip=" << localAddress->address_str(); -#ifdef RAK_USE_INET6 if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet6) { 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()); } -#endif if (info->is_compact()) s << "&compact=1"; @@ -340,13 +338,8 @@ TrackerHttp::process_success(const Object& object) { AddressList l; - if (!object.has_key("peers") -#ifdef RAK_USE_INET6 - && !object.has_key("peers6") -#endif - ) { + if (!object.has_key("peers") && !object.has_key("peers6")) return receive_failed("No peers returned"); - } if (object.has_key("peers")) { try { @@ -363,11 +356,8 @@ TrackerHttp::process_success(const Object& object) { } } -#ifdef RAK_USE_INET6 - if (object.has_key("peers6")) { + if (object.has_key("peers6")) l.parse_address_compact_ipv6(object.get_key_string("peers6")); - } -#endif close_directly(); m_parent->receive_success(this, &l); diff --git a/src/tracker/tracker_udp.cc b/src/tracker/tracker_udp.cc index 3bd5fc47c..aafca6702 100644 --- a/src/tracker/tracker_udp.cc +++ b/src/tracker/tracker_udp.cc @@ -337,16 +337,10 @@ TrackerUdp::prepare_announce_input() { const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address()); -#ifdef RAK_USE_INET6 uint32_t local_addr = 0; + if (localAddress->family() == rak::socket_address::af_inet) local_addr = localAddress->sa_inet()->address_n(); -#else - if (localAddress->family() != rak::socket_address::af_inet) - throw internal_error("TrackerUdp::prepare_announce_input() info->local_address() not of family AF_INET."); - - uint32_t local_addr = localAddress->sa_inet()->address_n(); -#endif m_writeBuffer->write_32_n(local_addr); m_writeBuffer->write_32(m_parent->key()); From e3b6ff447bc771885de59ea9fb3353e2cf4ebe08 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 6 Sep 2014 15:09:23 +0900 Subject: [PATCH 03/16] Fixed clang warnings. --- src/torrent/data/block_failed.h | 4 ++-- src/torrent/data/transfer_list.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/torrent/data/block_failed.h b/src/torrent/data/block_failed.h index 2e9fd1330..8337324a9 100644 --- a/src/torrent/data/block_failed.h +++ b/src/torrent/data/block_failed.h @@ -85,8 +85,8 @@ class BlockFailed : public std::vector > { BlockFailed(const BlockFailed&); void operator = (const BlockFailed&); - static void delete_entry(const reference e) { delete [] e.first; } - static bool compare_entries(const reference e1, const reference e2) { return e1.second < e2.second; } + static void delete_entry(value_type e) { delete [] e.first; } + static bool compare_entries(value_type e1, value_type e2) { return e1.second < e2.second; } size_type m_current; }; diff --git a/src/torrent/data/transfer_list.cc b/src/torrent/data/transfer_list.cc index fbbc91e86..74463c820 100644 --- a/src/torrent/data/transfer_list.cc +++ b/src/torrent/data/transfer_list.cc @@ -159,7 +159,7 @@ TransferList::hash_succeeded(uint32_t index, Chunk* chunk) { struct transfer_list_compare_data { transfer_list_compare_data(Chunk* chunk, const Piece& p) : m_chunk(chunk), m_piece(p) { } - bool operator () (const BlockFailed::reference failed) { + bool operator () (BlockFailed::value_type failed) { return m_chunk->compare_buffer(failed.first, m_piece.offset(), m_piece.length()); } From 06e8a5b282cc0b06a0f48f4d48a9d01b9f998bfc Mon Sep 17 00:00:00 2001 From: rakshasa Date: Mon, 15 Sep 2014 16:02:43 +0900 Subject: [PATCH 04/16] Updated authors and readme. --- AUTHORS | 2 +- README | 23 +++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/AUTHORS b/AUTHORS index 195fc222b..f9bdb537d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1 @@ -Jari Sundell +Jari Sundell diff --git a/README b/README index 6ebca06f0..76aa08ae1 100644 --- a/README +++ b/README @@ -1,5 +1,7 @@ LibTorrent +Copyright (C) 2005-2014, Jari Sundell + LICENSE GNU GPL, see COPYING. "libtorrent/src/utils/sha_fast.{cc,h}" is @@ -15,22 +17,11 @@ compiled if the user wishes to avoid using OpenSSL. CONTACT - Send bug reports, suggestions and patches to or -to the mailinglist. - -LIBRARY DEPENDENCIES - - g++ >= 4.2.1 - -SIGC++ + Jari Sundell - The API will use sigc++ signals to give the client a simple, yet -powerful way of reacting to events from the library. The client can -hook multiple slots on each signal and modify the parameters to suit -the functions. This avoids lots of unnecessary code in the client. + Skomakerveien 33 + 3185 Skoppum, NORWAY -POLLING + Send bug reports, suggestions and patches to + or to the mailinglist. - "libtorrent/src/torrent/poll.h" provides an abstract class for -implementing any kind of polling the client wishes to use. Currently -epoll and select based polling is included. From 62a72bcf2d60190c8335a8c4d52c9bde0b87bd65 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 18 Sep 2014 15:32:21 +0900 Subject: [PATCH 05/16] Update to inet6 sock address class. --- rak/socket_address.h | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/rak/socket_address.h b/rak/socket_address.h index 5f04785d1..6af82f4a3 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -205,6 +205,7 @@ class socket_address_inet6 { void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; } 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; @@ -235,42 +236,51 @@ class socket_address_inet6 { // Unique key for the address, excluding port numbers etc. class socket_address_key { public: -// socket_address_host_key() {} - socket_address_key(const socket_address& sa) { + socket_address_key(socket_address sa) { *this = sa; } socket_address_key& operator = (const socket_address& sa) { - if (sa.family() == 0) { - std::memset(this, 0, sizeof(socket_address_key)); + // Set all to 0 so we can use memcmp on the whole struct, instead + // of branching. + std::memset(this, 0, sizeof(socket_address_key)); - } else if (sa.family() == socket_address::af_inet) { - // Using hardware order as we use operator < to compare when - // using inet only. + m_family = sa.family(); + + if (sa.family() == socket_address::af_inet) { + // Using hardware order as we use operator < to compare in + // lexical order. m_addr.s_addr = sa.sa_inet()->address_h(); + } else if (sa.family() == socket_address::af_inet6) { + std::memcpy(&m_addr6, sa.sa_inet6()->address_ptr(), sizeof(in6_addr)); + } 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."); } return *this; } -// socket_address_key& operator = (const socket_address_key& sa) { -// } - bool operator < (const socket_address_key& sa) const { - // Compare the memory area instead. - return m_addr.s_addr < sa.m_addr.s_addr; - } + return std::memcmp(this, &sa, sizeof(socket_address_key)) < 0; + } + + bool operator > (const socket_address_key& sa) const { + return std::memcmp(this, &sa, sizeof(socket_address_key)) > 0; + } + + bool operator == (const socket_address_key& sa) const { + return std::memcmp(this, &sa, sizeof(socket_address_key)) == 0; + } private: + sa_family_t m_family; + union { in_addr m_addr; -// in_addr6 m_addr6; + in6_addr m_addr6; }; }; From 4a4e9719ee9551c6c8a947686433c7cb1f33da8a Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 18 Sep 2014 15:34:38 +0900 Subject: [PATCH 06/16] Added socket_address_key that does not depend on rak socket_adddress. --- src/torrent/utils/socket_address_key.h | 91 ++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/torrent/utils/socket_address_key.h diff --git a/src/torrent/utils/socket_address_key.h b/src/torrent/utils/socket_address_key.h new file mode 100644 index 000000000..dc6899e44 --- /dev/null +++ b/src/torrent/utils/socket_address_key.h @@ -0,0 +1,91 @@ +// Copyright (C) 2005-2014, Jari Sundell +// All rights reserved. + +#ifndef LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H +#define LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H + +// Unique key for the socket address, excluding port numbers, etc. + +// TODO: Add include files... + +namespace torrent { + +class LIBTORRENT_EXPORT socket_address_key { +public: + // TODO: Disable default ctor? + + // socket_address_key(const sockaddr* sa) : m_sockaddr(sa) {} + + bool is_valid() const { return m_family != AF_UNSPEC; } + + // // Rename, add same family, valid inet4/6. + + // TODO: Make from_sockaddr an rvalue reference. + static bool is_comparable_sockaddr(const sockaddr* sa); + static socket_address_key from_sockaddr(const sockaddr* sa); + + bool operator < (const socket_address_key& sa) const; + bool operator > (const socket_address_key& sa) const; + bool operator == (const socket_address_key& sa) const; + +private: + sa_family_t m_family; + + union { + in_addr m_addr; + in6_addr m_addr6; + }; +} __attribute__ ((packed)); + +inline bool +socket_address_key::is_comparable_sockaddr(const sockaddr* sa) { + return sa != NULL && (sa->sa_family == AF_INET || sa->sa_family == AF_INET6); +} + +inline socket_address_key +socket_address_key::from_sockaddr(const sockaddr* sa) { + socket_address_key result; + + result.m_family = AF_UNSPEC; + std::memset(&result, 0, sizeof(socket_address_key)); + + if (sa == NULL) + return result; + + switch (sa->sa_family) { + case AF_INET: + // Using hardware order to allo for the use of operator < to + // sort in lexical order. + result.m_family = AF_INET; + result.m_addr.s_addr = ntohl(reinterpret_cast(sa)->sin_addr.s_addr); + break; + + // case AF_INET6: + // result.m_family = AF_INET6; + // result.m_addr.s_addr = sa.sa_inet()->address_h(); + + default: + break; + } + + return result; +} + +inline bool +socket_address_key::operator < (const socket_address_key& sa) const { + return std::memcmp(this, &sa, sizeof(socket_address_key)) < 0; +} + +inline bool +socket_address_key::operator > (const socket_address_key& sa) const { + return std::memcmp(this, &sa, sizeof(socket_address_key)) > 0; +} + +inline bool +socket_address_key::operator == (const socket_address_key& sa) const { + return std::memcmp(this, &sa, sizeof(socket_address_key)) == 0; +} + +} + +#endif From abf37daabd12d2172702ae249fae2fe3066db872 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 18 Sep 2014 15:35:10 +0900 Subject: [PATCH 07/16] Updated peer_list to use new socket address key. --- src/torrent/peer/peer_list.cc | 38 ++++++++++++++++++++++------------- src/torrent/peer/peer_list.h | 16 +-------------- src/torrent/utils/Makefile.am | 2 ++ 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc index f2c08c4d2..fdcddf28d 100644 --- a/src/torrent/peer/peer_list.cc +++ b/src/torrent/peer/peer_list.cc @@ -62,6 +62,7 @@ namespace torrent { ipv4_table PeerList::m_ipv4_table; +// Clean up... bool socket_address_less(const sockaddr* s1, const sockaddr* s2) { const rak::socket_address* sa1 = rak::socket_address::cast_from(s1); @@ -86,11 +87,11 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) { } } -inline bool -socket_address_key::is_comparable(const sockaddr* sa) { - return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet || - rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6; -} +// inline bool +// socket_address_key::is_comparable(const sockaddr* sa) { +// return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet || +// rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6; +// } struct peer_list_equal_port : public std::binary_function { bool operator () (PeerList::reference p, uint16_t port) { @@ -126,14 +127,17 @@ PeerList::set_info(DownloadInfo* info) { PeerInfo* PeerList::insert_address(const sockaddr* sa, int flags) { - if (!socket_address_key::is_comparable(sa)) { + socket_address_key sock_key = socket_address_key::from_sockaddr(sa); + + if (sock_key.is_valid() && + !socket_address_key::is_comparable_sockaddr(sa)) { LT_LOG_EVENTS("address not comparable", 0); return NULL; } const rak::socket_address* address = rak::socket_address::cast_from(sa); - range_type range = base_type::equal_range(sa); + range_type range = base_type::equal_range(sock_key); // Do some special handling if we got a new port number but the // address was present. @@ -152,7 +156,7 @@ PeerList::insert_address(const sockaddr* sa, int flags) { manager->client_list()->retrieve_unknown(&peerInfo->mutable_client_info()); - base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo)); + base_type::insert(range.second, value_type(sock_key, peerInfo)); if ((flags & address_available) && peerInfo->listen_port() != 0) { m_available_list->push_back(address); @@ -192,7 +196,7 @@ PeerList::insert_available(const void* al) { AvailableList::const_iterator availLast = m_available_list->end(); for (; itr != last; itr++) { - if (!socket_address_key::is_comparable(itr->c_sockaddr()) || itr->port() == 0) { + if (!socket_address_key::is_comparable_sockaddr(itr->c_sockaddr()) || itr->port() == 0) { invalid++; continue; } @@ -206,11 +210,13 @@ PeerList::insert_available(const void* al) { continue; } + socket_address_key sock_key = socket_address_key::from_sockaddr(itr->c_sockaddr()); + // Check if the peerinfo exists, if it does, check if we would // ever want to connect. Just update the timer for the last // availability notice if the peer isn't really ideal, but might // be used in an emergency. - range_type range = base_type::equal_range(itr->c_sockaddr()); + range_type range = base_type::equal_range(sock_key); if (range.first != range.second) { // Add some logic here to select the best PeerInfo, but for now @@ -258,8 +264,10 @@ PeerList::available_list_size() const { PeerInfo* PeerList::connected(const sockaddr* sa, int flags) { const rak::socket_address* address = rak::socket_address::cast_from(sa); + socket_address_key sock_key = socket_address_key::from_sockaddr(sa); - if (!socket_address_key::is_comparable(sa)) + if (!sock_key.is_valid() || + !socket_address_key::is_comparable_sockaddr(sa)) return NULL; int filter_value = m_ipv4_table.at(address->sa_inet()->address_h()); @@ -270,14 +278,14 @@ PeerList::connected(const sockaddr* sa, int flags) { return NULL; PeerInfo* peerInfo; - range_type range = base_type::equal_range(sa); + range_type range = base_type::equal_range(sock_key); if (range.first == range.second) { // Create a new entry. peerInfo = new PeerInfo(sa); peerInfo->set_flags(filter_value & PeerInfo::mask_ip_table); - base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo)); + base_type::insert(range.second, value_type(sock_key, peerInfo)); } else if (!range.first->second->is_connected()) { // Use an old entry. @@ -321,7 +329,9 @@ PeerList::connected(const sockaddr* sa, int flags) { void PeerList::disconnected(PeerInfo* p, int flags) { - range_type range = base_type::equal_range(p->socket_address()); + socket_address_key sock_key = socket_address_key::from_sockaddr(p->socket_address()); + + range_type range = base_type::equal_range(sock_key); iterator itr = std::find_if(range.first, range.second, rak::equal(p, rak::mem_ref(&value_type::second))); diff --git a/src/torrent/peer/peer_list.h b/src/torrent/peer/peer_list.h index 1d63bc3f5..89fc90440 100644 --- a/src/torrent/peer/peer_list.h +++ b/src/torrent/peer/peer_list.h @@ -40,6 +40,7 @@ #include #include #include +#include namespace torrent { @@ -47,21 +48,6 @@ class DownloadInfo; typedef extents ipv4_table; -bool socket_address_less(const sockaddr* s1, const sockaddr* s2); - -// Unique key for the address, excluding port numbers etc. -class LIBTORRENT_EXPORT socket_address_key { -public: - socket_address_key(const sockaddr* sa) : m_sockaddr(sa) {} - - inline static bool is_comparable(const sockaddr* sa); - - bool operator < (const socket_address_key& sa) const { return socket_address_less(m_sockaddr, sa.m_sockaddr); } - -private: - const sockaddr* m_sockaddr; -}; - class LIBTORRENT_EXPORT PeerList : private std::multimap { public: friend class DownloadWrapper; diff --git a/src/torrent/utils/Makefile.am b/src/torrent/utils/Makefile.am index 51c9a0266..6370323e3 100644 --- a/src/torrent/utils/Makefile.am +++ b/src/torrent/utils/Makefile.am @@ -17,6 +17,7 @@ libsub_torrentutils_la_SOURCES = \ resume.h \ signal_bitfield.cc \ signal_bitfield.h \ + socket_address_key.h \ thread_base.cc \ thread_base.h \ thread_interrupt.cc \ @@ -37,6 +38,7 @@ libtorrentinclude_HEADERS = \ ranges.h \ resume.h \ signal_bitfield.h \ + socket_address_key.h \ thread_base.h \ thread_interrupt.h \ uri_parser.h From c02721df1bf7b370bb34355607a34ff1c4b98c22 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 18 Sep 2014 15:35:27 +0900 Subject: [PATCH 08/16] Added test classes for socket_address_key. --- test/torrent/utils/test_socket_address_key.cc | 16 ++++++++++++++++ test/torrent/utils/test_socket_address_key.h | 15 +++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 test/torrent/utils/test_socket_address_key.cc create mode 100644 test/torrent/utils/test_socket_address_key.h diff --git a/test/torrent/utils/test_socket_address_key.cc b/test/torrent/utils/test_socket_address_key.cc new file mode 100644 index 000000000..5598b47d0 --- /dev/null +++ b/test/torrent/utils/test_socket_address_key.cc @@ -0,0 +1,16 @@ +#include "config.h" + +#include "test_socket_address_key.h" + +#include "utils/instrumentation.h" +#include "utils/queue_buckets.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(TestSocketAddressKey); + +// +// Basic tests: +// + +void +TestSocketAddressKey::test_basic() { +} diff --git a/test/torrent/utils/test_socket_address_key.h b/test/torrent/utils/test_socket_address_key.h new file mode 100644 index 000000000..12cfcd4d4 --- /dev/null +++ b/test/torrent/utils/test_socket_address_key.h @@ -0,0 +1,15 @@ +#include + +#include "protocol/request_list.h" + +class TestSocketAddressKey : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestSocketAddressKey); + CPPUNIT_TEST(test_basic); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() {} + void tearDown() {} + + void test_basic(); +}; From 099d220c59e8451aacb5e09db98454b71744cbf0 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 19 Sep 2014 15:35:24 +0900 Subject: [PATCH 09/16] Added tests for basic inet4 address lookup tests. --- src/torrent/utils/socket_address_key.h | 2 + test/Makefile.am | 2 + test/torrent/utils/test_socket_address_key.cc | 70 ++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/torrent/utils/socket_address_key.h b/src/torrent/utils/socket_address_key.h index dc6899e44..4cccf9e1b 100644 --- a/src/torrent/utils/socket_address_key.h +++ b/src/torrent/utils/socket_address_key.h @@ -42,6 +42,8 @@ socket_address_key::is_comparable_sockaddr(const sockaddr* sa) { return sa != NULL && (sa->sa_family == AF_INET || sa->sa_family == AF_INET6); } +// TODO: Require socket length? + inline socket_address_key socket_address_key::from_sockaddr(const sockaddr* sa) { socket_address_key result; diff --git a/test/Makefile.am b/test/Makefile.am index f2b2500d4..b9770cc71 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -67,6 +67,8 @@ LibTorrentTest_SOURCES = \ torrent/utils/test_extents.h \ torrent/utils/test_queue_buckets.cc \ torrent/utils/test_queue_buckets.h \ + torrent/utils/test_socket_address_key.cc \ + torrent/utils/test_socket_address_key.h \ torrent/utils/test_uri_parser.cc \ torrent/utils/test_uri_parser.h \ torrent/utils/signal_bitfield_test.cc \ diff --git a/test/torrent/utils/test_socket_address_key.cc b/test/torrent/utils/test_socket_address_key.cc index 5598b47d0..d398ca294 100644 --- a/test/torrent/utils/test_socket_address_key.cc +++ b/test/torrent/utils/test_socket_address_key.cc @@ -1,16 +1,82 @@ #include "config.h" +#include lt_tr1_functional +#include +#include + #include "test_socket_address_key.h" -#include "utils/instrumentation.h" -#include "utils/queue_buckets.h" +#include "torrent/utils/net.h" +#include "torrent/utils/socket_address_key.h" CPPUNIT_TEST_SUITE_REGISTRATION(TestSocketAddressKey); +// TODO: Move into a test utilities header: + +typedef std::function 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)); +} + // // Basic tests: // void TestSocketAddressKey::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("1.1.1.1").is_valid()); } + + +// Test lexical comparison: From 0500ef7dc838bef182549cd42b35b401717d7ed4 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 19 Sep 2014 16:57:08 +0900 Subject: [PATCH 10/16] Added conversion of inet6 to socket address key. --- src/torrent/utils/socket_address_key.h | 9 ++++++--- test/torrent/utils/test_socket_address_key.cc | 4 ++-- test/torrent/utils/test_socket_address_key.h | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/torrent/utils/socket_address_key.h b/src/torrent/utils/socket_address_key.h index 4cccf9e1b..dee557bea 100644 --- a/src/torrent/utils/socket_address_key.h +++ b/src/torrent/utils/socket_address_key.h @@ -62,9 +62,10 @@ socket_address_key::from_sockaddr(const sockaddr* sa) { result.m_addr.s_addr = ntohl(reinterpret_cast(sa)->sin_addr.s_addr); break; - // case AF_INET6: - // result.m_family = AF_INET6; - // result.m_addr.s_addr = sa.sa_inet()->address_h(); + case AF_INET6: + result.m_family = AF_INET6; + result.m_addr6 = reinterpret_cast(sa)->sin6_addr; + break; default: break; @@ -73,6 +74,8 @@ socket_address_key::from_sockaddr(const sockaddr* sa) { return result; } +// TODO: Add sockaddr_in/in6. + inline bool socket_address_key::operator < (const socket_address_key& sa) const { return std::memcmp(this, &sa, sizeof(socket_address_key)) < 0; diff --git a/test/torrent/utils/test_socket_address_key.cc b/test/torrent/utils/test_socket_address_key.cc index d398ca294..212b7e6e4 100644 --- a/test/torrent/utils/test_socket_address_key.cc +++ b/test/torrent/utils/test_socket_address_key.cc @@ -9,7 +9,7 @@ #include "torrent/utils/net.h" #include "torrent/utils/socket_address_key.h" -CPPUNIT_TEST_SUITE_REGISTRATION(TestSocketAddressKey); +CPPUNIT_TEST_SUITE_REGISTRATION(test_socket_address_key); // TODO: Move into a test utilities header: @@ -67,7 +67,7 @@ test_create_inet6(const char* hostname) { // void -TestSocketAddressKey::test_basic() { +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")); diff --git a/test/torrent/utils/test_socket_address_key.h b/test/torrent/utils/test_socket_address_key.h index 12cfcd4d4..75913bfa4 100644 --- a/test/torrent/utils/test_socket_address_key.h +++ b/test/torrent/utils/test_socket_address_key.h @@ -2,8 +2,8 @@ #include "protocol/request_list.h" -class TestSocketAddressKey : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(TestSocketAddressKey); +class test_socket_address_key : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(test_socket_address_key); CPPUNIT_TEST(test_basic); CPPUNIT_TEST_SUITE_END(); From 54fa023d5c51f17cf3a550c91ce7d9c092fe24fe Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 20 Sep 2014 17:41:32 +0900 Subject: [PATCH 11/16] Added direct conversion from sin_addr and sin6_addr to socket_address_key. --- src/torrent/utils/socket_address_key.h | 30 +++++++++++++++++-- test/torrent/utils/test_socket_address_key.cc | 7 ++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/torrent/utils/socket_address_key.h b/src/torrent/utils/socket_address_key.h index dee557bea..652bcef09 100644 --- a/src/torrent/utils/socket_address_key.h +++ b/src/torrent/utils/socket_address_key.h @@ -22,7 +22,10 @@ class LIBTORRENT_EXPORT socket_address_key { // TODO: Make from_sockaddr an rvalue reference. static bool is_comparable_sockaddr(const sockaddr* sa); + static socket_address_key from_sockaddr(const sockaddr* sa); + static socket_address_key from_sin_addr(const sockaddr_in& sa); + static socket_address_key from_sin6_addr(const sockaddr_in6& sa); bool operator < (const socket_address_key& sa) const; bool operator > (const socket_address_key& sa) const; @@ -48,9 +51,10 @@ inline socket_address_key socket_address_key::from_sockaddr(const sockaddr* sa) { socket_address_key result; - result.m_family = AF_UNSPEC; std::memset(&result, 0, sizeof(socket_address_key)); + result.m_family = AF_UNSPEC; + if (sa == NULL) return result; @@ -74,7 +78,29 @@ socket_address_key::from_sockaddr(const sockaddr* sa) { return result; } -// TODO: Add sockaddr_in/in6. +inline socket_address_key +socket_address_key::from_sin_addr(const sockaddr_in& sa) { + socket_address_key result; + + std::memset(&result, 0, sizeof(socket_address_key)); + + result.m_family = AF_INET; + result.m_addr.s_addr = ntohl(sa.sin_addr.s_addr); + + return result; +} + +inline socket_address_key +socket_address_key::from_sin6_addr(const sockaddr_in6& sa) { + socket_address_key result; + + std::memset(&result, 0, sizeof(socket_address_key)); + + result.m_family = AF_INET6; + result.m_addr6 = sa.sin6_addr; + + return result; +} inline bool socket_address_key::operator < (const socket_address_key& sa) const { diff --git a/test/torrent/utils/test_socket_address_key.cc b/test/torrent/utils/test_socket_address_key.cc index 212b7e6e4..78d44a7ba 100644 --- a/test/torrent/utils/test_socket_address_key.cc +++ b/test/torrent/utils/test_socket_address_key.cc @@ -62,6 +62,11 @@ 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: // @@ -75,7 +80,7 @@ test_socket_address_key::test_basic() { 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("1.1.1.1").is_valid()); + CPPUNIT_ASSERT(test_create_inet6_throws("2001:db8:a::22123")); } From 1711b35cfc78d0e7c5ad1dcc9464fb34712f86d5 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 20 Sep 2014 17:45:28 +0900 Subject: [PATCH 12/16] Removed socket_address_key from rak headers. --- rak/socket_address.h | 51 -------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/rak/socket_address.h b/rak/socket_address.h index 6af82f4a3..d1d5b7224 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -233,57 +233,6 @@ class socket_address_inet6 { struct sockaddr_in6 m_sockaddr; }; -// Unique key for the address, excluding port numbers etc. -class socket_address_key { -public: - - socket_address_key(socket_address sa) { - *this = sa; - } - - socket_address_key& operator = (const socket_address& sa) { - // Set all to 0 so we can use memcmp on the whole struct, instead - // of branching. - std::memset(this, 0, sizeof(socket_address_key)); - - m_family = sa.family(); - - if (sa.family() == socket_address::af_inet) { - // Using hardware order as we use operator < to compare in - // lexical order. - m_addr.s_addr = sa.sa_inet()->address_h(); - - } else if (sa.family() == socket_address::af_inet6) { - std::memcpy(&m_addr6, sa.sa_inet6()->address_ptr(), sizeof(in6_addr)); - - } else { - throw std::logic_error("socket_address_key(...) received an unsupported protocol family."); - } - - return *this; - } - - bool operator < (const socket_address_key& sa) const { - return std::memcmp(this, &sa, sizeof(socket_address_key)) < 0; - } - - bool operator > (const socket_address_key& sa) const { - return std::memcmp(this, &sa, sizeof(socket_address_key)) > 0; - } - - bool operator == (const socket_address_key& sa) const { - return std::memcmp(this, &sa, sizeof(socket_address_key)) == 0; - } - -private: - sa_family_t m_family; - - union { - in_addr m_addr; - in6_addr m_addr6; - }; -}; - inline bool socket_address::is_valid() const { switch (family()) { From a6b67331aebc25960b9b56a6cbb0edba757349c4 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 23 Sep 2014 16:57:53 +0900 Subject: [PATCH 13/16] Moved network related headers to torrent/net. --- configure.ac | 3 +- src/Makefile.am | 1 + src/torrent/Makefile.am | 1 + src/torrent/net/Makefile.am | 11 +++++ src/torrent/net/socket_address_key.cc | 5 +++ .../{utils => net}/socket_address_key.h | 0 src/torrent/peer/peer_list.h | 2 +- src/torrent/utils/Makefile.am | 2 - test/Makefile.am | 43 ++++++++++--------- .../{utils => net}/test_socket_address_key.cc | 2 +- .../{utils => net}/test_socket_address_key.h | 0 11 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 src/torrent/net/Makefile.am create mode 100644 src/torrent/net/socket_address_key.cc rename src/torrent/{utils => net}/socket_address_key.h (100%) rename test/torrent/{utils => net}/test_socket_address_key.cc (98%) rename test/torrent/{utils => net}/test_socket_address_key.h (100%) diff --git a/configure.ac b/configure.ac index 05d56db97..0e7420fb5 100644 --- a/configure.ac +++ b/configure.ac @@ -125,9 +125,10 @@ AC_OUTPUT([ Makefile src/Makefile src/torrent/Makefile - src/torrent/peer/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 diff --git a/src/Makefile.am b/src/Makefile.am index 110da5ac3..99aaace0a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,7 @@ 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 \ diff --git a/src/torrent/Makefile.am b/src/torrent/Makefile.am index cea5b728f..1bdfde3de 100644 --- a/src/torrent/Makefile.am +++ b/src/torrent/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = \ data \ download \ + net \ peer \ utils diff --git a/src/torrent/net/Makefile.am b/src/torrent/net/Makefile.am new file mode 100644 index 000000000..51999d196 --- /dev/null +++ b/src/torrent/net/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libsub_torrentnet.la + +libsub_torrentnet_la_SOURCES = \ + socket_address_key.cc \ + socket_address_key.h + +AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(top_srcdir) + +libtorrentincludedir = $(includedir)/torrent/net +libtorrentinclude_HEADERS = \ + socket_address_key.h diff --git a/src/torrent/net/socket_address_key.cc b/src/torrent/net/socket_address_key.cc new file mode 100644 index 000000000..f5e0d3ba6 --- /dev/null +++ b/src/torrent/net/socket_address_key.cc @@ -0,0 +1,5 @@ +// Copyright (C) 2005-2014, Jari Sundell +// All rights reserved. + +#include "config.h" + diff --git a/src/torrent/utils/socket_address_key.h b/src/torrent/net/socket_address_key.h similarity index 100% rename from src/torrent/utils/socket_address_key.h rename to src/torrent/net/socket_address_key.h diff --git a/src/torrent/peer/peer_list.h b/src/torrent/peer/peer_list.h index 89fc90440..a3b409cb9 100644 --- a/src/torrent/peer/peer_list.h +++ b/src/torrent/peer/peer_list.h @@ -39,8 +39,8 @@ #include #include +#include #include -#include namespace torrent { diff --git a/src/torrent/utils/Makefile.am b/src/torrent/utils/Makefile.am index 6370323e3..51c9a0266 100644 --- a/src/torrent/utils/Makefile.am +++ b/src/torrent/utils/Makefile.am @@ -17,7 +17,6 @@ libsub_torrentutils_la_SOURCES = \ resume.h \ signal_bitfield.cc \ signal_bitfield.h \ - socket_address_key.h \ thread_base.cc \ thread_base.h \ thread_interrupt.cc \ @@ -38,7 +37,6 @@ libtorrentinclude_HEADERS = \ ranges.h \ resume.h \ signal_bitfield.h \ - socket_address_key.h \ thread_base.h \ thread_interrupt.h \ uri_parser.h diff --git a/test/Makefile.am b/test/Makefile.am index b9770cc71..d7a9d5b3b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -33,6 +33,29 @@ LibTorrentTest_SOURCES = \ data/hash_queue_test.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/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_queue_buckets.cc \ + torrent/utils/test_queue_buckets.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/http_test.cc \ torrent/http_test.h \ torrent/object_test.cc \ @@ -55,26 +78,6 @@ LibTorrentTest_SOURCES = \ torrent/tracker_list_features_test.h \ torrent/tracker_timeout_test.cc \ torrent/tracker_timeout_test.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_queue_buckets.cc \ - torrent/utils/test_queue_buckets.h \ - torrent/utils/test_socket_address_key.cc \ - torrent/utils/test_socket_address_key.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 \ tracker/tracker_http_test.cc \ tracker/tracker_http_test.h \ main.cc diff --git a/test/torrent/utils/test_socket_address_key.cc b/test/torrent/net/test_socket_address_key.cc similarity index 98% rename from test/torrent/utils/test_socket_address_key.cc rename to test/torrent/net/test_socket_address_key.cc index 78d44a7ba..7892e730e 100644 --- a/test/torrent/utils/test_socket_address_key.cc +++ b/test/torrent/net/test_socket_address_key.cc @@ -7,7 +7,7 @@ #include "test_socket_address_key.h" #include "torrent/utils/net.h" -#include "torrent/utils/socket_address_key.h" +#include "torrent/net/socket_address_key.h" CPPUNIT_TEST_SUITE_REGISTRATION(test_socket_address_key); diff --git a/test/torrent/utils/test_socket_address_key.h b/test/torrent/net/test_socket_address_key.h similarity index 100% rename from test/torrent/utils/test_socket_address_key.h rename to test/torrent/net/test_socket_address_key.h From ad95b31c1aa0bbcabb56e8f4433262e7b4bdb527 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 23 Sep 2014 19:49:36 +0900 Subject: [PATCH 14/16] Use inet6 if bind is not set. --- src/net/listen.cc | 11 +++++++++-- src/torrent/net/socket_address_key.h | 6 +++++- src/torrent/peer/peer_list.cc | 8 +------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/net/listen.cc b/src/net/listen.cc index 79c52f421..da1c2e846 100644 --- a/src/net/listen.cc +++ b/src/net/listen.cc @@ -61,7 +61,8 @@ Listen::open(uint16_t first, uint16_t last, int backlog, const rak::socket_addre if (first == 0 || first > last) throw input_error("Tried to open listening port with an invalid range."); - if (bindAddress->family() != rak::socket_address::af_inet && + if (bindAddress->family() != 0 && + bindAddress->family() != rak::socket_address::af_inet && bindAddress->family() != rak::socket_address::af_inet6) throw input_error("Listening socket must be bound to an inet or inet6 address."); @@ -71,7 +72,13 @@ Listen::open(uint16_t first, uint16_t last, int backlog, const rak::socket_addre throw resource_error("Could not allocate socket for listening."); rak::socket_address sa; - sa.copy(*bindAddress, bindAddress->length()); + + // TODO: Temporary until we refactor: + if (bindAddress->family() == 0) { + sa.sa_inet6()->clear(); + } else { + sa.copy(*bindAddress, bindAddress->length()); + } do { sa.set_port(first); diff --git a/src/torrent/net/socket_address_key.h b/src/torrent/net/socket_address_key.h index 652bcef09..b17b1cdcf 100644 --- a/src/torrent/net/socket_address_key.h +++ b/src/torrent/net/socket_address_key.h @@ -4,13 +4,17 @@ #ifndef LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H #define LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H +#include +#include +#include + // Unique key for the socket address, excluding port numbers, etc. // TODO: Add include files... namespace torrent { -class LIBTORRENT_EXPORT socket_address_key { +class socket_address_key { public: // TODO: Disable default ctor? diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc index fdcddf28d..23ca651a2 100644 --- a/src/torrent/peer/peer_list.cc +++ b/src/torrent/peer/peer_list.cc @@ -62,7 +62,7 @@ namespace torrent { ipv4_table PeerList::m_ipv4_table; -// Clean up... +// TODO: Clean up... bool socket_address_less(const sockaddr* s1, const sockaddr* s2) { const rak::socket_address* sa1 = rak::socket_address::cast_from(s1); @@ -87,12 +87,6 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) { } } -// inline bool -// socket_address_key::is_comparable(const sockaddr* sa) { -// return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet || -// rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6; -// } - struct peer_list_equal_port : public std::binary_function { bool operator () (PeerList::reference p, uint16_t port) { return rak::socket_address::cast_from(p.second->socket_address())->port() == port; From 11b6b4f58e19064717995403995b5cc7f4b95fc1 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 24 Sep 2014 18:37:41 +0900 Subject: [PATCH 15/16] Fixed missing header files. --- src/torrent/net/socket_address_compact.h | 58 ++++++++++++++++++++++++ src/torrent/net/socket_address_key.h | 2 +- test/main.cc | 1 + 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/torrent/net/socket_address_compact.h diff --git a/src/torrent/net/socket_address_compact.h b/src/torrent/net/socket_address_compact.h new file mode 100644 index 000000000..44474efac --- /dev/null +++ b/src/torrent/net/socket_address_compact.h @@ -0,0 +1,58 @@ +// Copyright (C) 2005-2014, Jari Sundell +// All rights reserved. + +#ifndef LIBTORRENT_UTILS_SOCKET_ADDRESS_COMPACT_H +#define LIBTORRENT_UTILS_SOCKET_ADDRESS_COMPACT_H + +// Unique key for the socket address, excluding port numbers, etc. + +// TODO: Add include files... + +#include + +namespace torrent { + +struct socket_address_compact { + socket_address_compact() {} + socket_address_compact(uint32_t a, uint16_t p) : addr(a), port(p) {} + socket_address_compact(const rak::socket_address_inet* sa) : addr(sa->address_n()), port(sa->port_n()) {} + + operator rak::socket_address () const { + rak::socket_address sa; + sa.sa_inet()->clear(); + sa.sa_inet()->set_port_n(port); + sa.sa_inet()->set_address_n(addr); + + return sa; + } + + uint32_t addr; + uint16_t port; + + // TODO: c_str? should be c_ptr or something. + const char* c_str() const { return reinterpret_cast(this); } +} __attribute__ ((packed)); + +struct socket_address_compact6 { + socket_address_compact6() {} + socket_address_compact6(in6_addr a, uint16_t p) : addr(a), port(p) {} + socket_address_compact6(const rak::socket_address_inet6* sa) : addr(sa->address()), port(sa->port_n()) {} + + operator rak::socket_address () const { + rak::socket_address sa; + sa.sa_inet6()->clear(); + sa.sa_inet6()->set_port_n(port); + sa.sa_inet6()->set_address(addr); + + return sa; + } + + in6_addr addr; + uint16_t port; + + const char* c_str() const { return reinterpret_cast(this); } +} __attribute__ ((packed)); + +} + +#endif diff --git a/src/torrent/net/socket_address_key.h b/src/torrent/net/socket_address_key.h index b17b1cdcf..9d6e0c49a 100644 --- a/src/torrent/net/socket_address_key.h +++ b/src/torrent/net/socket_address_key.h @@ -4,7 +4,7 @@ #ifndef LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H #define LIBTORRENT_UTILS_SOCKET_ADDRESS_KEY_H -#include +#include #include #include diff --git a/test/main.cc b/test/main.cc index 51b84de37..e69d3d709 100644 --- a/test/main.cc +++ b/test/main.cc @@ -1,3 +1,4 @@ +#include #include #include #include From b80b5580cd77aaf5399a12588402c25b806b5f27 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 28 Oct 2014 20:17:37 +0900 Subject: [PATCH 16/16] Fixed link local addresses. --- src/net/local_addr.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc index db40a84f1..1682e5f86 100644 --- a/src/net/local_addr.cc +++ b/src/net/local_addr.cc @@ -60,7 +60,7 @@ 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/16, 192.168.0.0/24) +// 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) @@ -69,14 +69,14 @@ get_priority_ipv4(const in_addr& addr) { if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x7f000000U)) { return 5; } - if (addr.s_addr == htonl(0)) { + if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) { return 4; } - if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) { + if (addr.s_addr == htonl(0)) { return 3; } if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x0a000000U) || - (addr.s_addr & htonl(0xffff0000U)) == htonl(0xac100000U) || + (addr.s_addr & htonl(0xfff00000U)) == htonl(0xac100000U) || (addr.s_addr & htonl(0xffff0000U)) == htonl(0xc0a80000U)) { return 2; }