1 diff --git a/rak/socket_address.h b/rak/socket_address.h
2 index 25fdb37..d38533e 100644
3 --- a/rak/socket_address.h
4 +++ b/rak/socket_address.h
5 @@ -145,7 +145,7 @@ private:
9 -// Remeber to set the AF_INET.
10 +// Remember to set the AF_INET.
12 class socket_address_inet {
14 @@ -184,6 +184,10 @@ public:
16 const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
17 const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
20 + socket_address_inet6 to_mapped_address() const;
23 bool operator == (const socket_address_inet& rhs) const;
24 bool operator < (const socket_address_inet& rhs) const;
25 @@ -192,6 +196,52 @@ private:
26 struct sockaddr_in m_sockaddr;
30 +// Remember to set the AF_INET6.
32 +class socket_address_inet6 {
34 + bool is_any() const { return is_port_any() && is_address_any(); }
35 + bool is_valid() const { return !is_port_any() && !is_address_any(); }
36 + bool is_port_any() const { return port() == 0; }
37 + bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
39 + void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
41 + uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
42 + uint16_t port_n() const { return m_sockaddr.sin6_port; }
43 + void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
44 + void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
46 + in6_addr address() const { return m_sockaddr.sin6_addr; }
47 + std::string address_str() const;
48 + bool address_c_str(char* buf, socklen_t size) const;
50 + void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
51 + bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
52 + bool set_address_c_str(const char* a);
54 + void set_address_any() { set_port(0); set_address(in6addr_any); }
56 + sa_family_t family() const { return m_sockaddr.sin6_family; }
57 + void set_family() { m_sockaddr.sin6_family = AF_INET6; }
59 + sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
60 + sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
62 + const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
63 + const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
65 + socket_address normalize_address() const;
67 + bool operator == (const socket_address_inet6& rhs) const;
68 + bool operator < (const socket_address_inet6& rhs) const;
71 + struct sockaddr_in6 m_sockaddr;
75 // Unique key for the address, excluding port numbers etc.
76 class socket_address_key {
78 @@ -241,8 +291,10 @@ socket_address::is_valid() const {
81 return sa_inet()->is_valid();
83 -// return sa_inet6().is_valid();
86 + return sa_inet6()->is_valid();
91 @@ -253,6 +305,10 @@ socket_address::is_bindable() const {
94 return !sa_inet()->is_address_any();
97 + return !sa_inet6()->is_address_any();
102 @@ -263,6 +319,10 @@ socket_address::is_address_any() const {
105 return sa_inet()->is_address_any();
106 +#ifdef RAK_USE_INET6
108 + return sa_inet6()->is_address_any();
113 @@ -273,6 +333,10 @@ socket_address::port() const {
116 return sa_inet()->port();
117 +#ifdef RAK_USE_INET6
119 + return sa_inet6()->port();
124 @@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) {
127 return sa_inet()->set_port(p);
128 +#ifdef RAK_USE_INET6
130 + return sa_inet6()->set_port(p);
135 @@ -293,6 +361,10 @@ socket_address::address_str() const {
138 return sa_inet()->address_str();
139 +#ifdef RAK_USE_INET6
141 + return sa_inet6()->address_str();
144 return std::string();
146 @@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
149 return sa_inet()->address_c_str(buf, size);
150 +#ifdef RAK_USE_INET6
152 + return sa_inet6()->address_c_str(buf, size);
157 @@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) {
158 sa_inet()->set_family();
161 +#ifdef RAK_USE_INET6
162 + } else if (sa_inet6()->set_address_c_str(a)) {
163 + sa_inet6()->set_family();
170 @@ -325,6 +407,10 @@ socket_address::length() const {
173 return sizeof(sockaddr_in);
174 +#ifdef RAK_USE_INET6
176 + return sizeof(sockaddr_in6);
181 @@ -349,8 +435,10 @@ socket_address::operator == (const socket_address& rhs) const {
184 return *sa_inet() == *rhs.sa_inet();
186 -// return *sa_inet6() == *rhs.sa_inet6();
187 +#ifdef RAK_USE_INET6
189 + return *sa_inet6() == *rhs.sa_inet6();
192 throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
194 @@ -364,8 +452,10 @@ socket_address::operator < (const socket_address& rhs) const {
197 return *sa_inet() < *rhs.sa_inet();
199 -// return *sa_inet6() < *rhs.sa_inet6();
200 +#ifdef RAK_USE_INET6
202 + return *sa_inet6() < *rhs.sa_inet6();
205 throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
207 @@ -391,6 +481,23 @@ socket_address_inet::set_address_c_str(const char* a) {
208 return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
211 +#ifdef RAK_USE_INET6
212 +inline socket_address_inet6
213 +socket_address_inet::to_mapped_address() const {
214 + uint32_t addr32[4];
217 + addr32[2] = htonl(0xffff);
218 + addr32[3] = m_sockaddr.sin_addr.s_addr;
220 + socket_address_inet6 sa;
222 + sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
223 + sa.set_port_n(m_sockaddr.sin_port);
229 socket_address_inet::operator == (const socket_address_inet& rhs) const {
231 @@ -406,6 +513,59 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
232 m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
235 +#ifdef RAK_USE_INET6
238 +socket_address_inet6::address_str() const {
239 + char buf[INET6_ADDRSTRLEN];
241 + if (!address_c_str(buf, INET6_ADDRSTRLEN))
242 + return std::string();
244 + return std::string(buf);
248 +socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
249 + return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
253 +socket_address_inet6::set_address_c_str(const char* a) {
254 + return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
257 +inline socket_address
258 +socket_address_inet6::normalize_address() const {
259 + const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
260 + if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
261 + socket_address addr4;
262 + addr4.sa_inet()->set_family();
263 + addr4.sa_inet()->set_address_n(addr32[3]);
264 + addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
267 + return *reinterpret_cast<const socket_address*>(this);
271 +socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
273 + memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
274 + m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
278 +socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
279 + int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
283 + m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
291 diff --git a/src/dht/dht_node.cc b/src/dht/dht_node.cc
292 index 9d51a28..e0eb306 100644
293 --- a/src/dht/dht_node.cc
294 +++ b/src/dht/dht_node.cc
295 @@ -55,8 +55,15 @@ DhtNode::DhtNode(const HashString& id, const rak::socket_address* sa) :
296 m_recentlyInactive(0),
299 +#ifdef RAK_USE_INET6
300 + if (sa->family() != rak::socket_address::af_inet &&
301 + (sa->family() != rak::socket_address::af_inet6 ||
302 + !sa->sa_inet6()->is_any()))
303 + throw resource_error("Address not af_inet or in6addr_any");
305 if (sa->family() != rak::socket_address::af_inet)
306 throw resource_error("Address not af_inet");
310 DhtNode::DhtNode(const SimpleString& id, const Object& cache) :
311 @@ -85,8 +92,20 @@ DhtNode::store_compact(char* buffer) const {
314 DhtNode::store_cache(Object* container) const {
315 - container->insert_key("i", m_socketAddress.sa_inet()->address_h());
316 - container->insert_key("p", m_socketAddress.sa_inet()->port());
317 +#ifdef RAK_USE_INET6
318 + if (m_socketAddress.family() == rak::socket_address::af_inet6) {
319 + // Currently, all we support is in6addr_any (checked in the constructor),
320 + // which is effectively equivalent to this. Note that we need to specify
321 + // int64_t explicitly here because a zero constant is special in C++ and
322 + // thus we need an explicit match.
323 + container->insert_key("i", int64_t(0));
324 + container->insert_key("p", m_socketAddress.sa_inet6()->port());
328 + container->insert_key("i", m_socketAddress.sa_inet()->address_h());
329 + container->insert_key("p", m_socketAddress.sa_inet()->port());
331 container->insert_key("t", m_lastSeen);
334 diff --git a/src/dht/dht_server.cc b/src/dht/dht_server.cc
335 index 256b92b..8c8b380 100644
336 --- a/src/dht/dht_server.cc
337 +++ b/src/dht/dht_server.cc
338 @@ -692,6 +692,16 @@ DhtServer::event_read() {
342 +#ifdef RAK_USE_INET6
343 + // We can currently only process mapped-IPv4 addresses, not real IPv6.
344 + // Translate them to an af_inet socket_address.
345 + if (sa.family() == rak::socket_address::af_inet6)
346 + sa = sa.sa_inet6()->normalize_address();
349 + if (sa.family() != rak::socket_address::af_inet)
354 // If it's not a valid bencode dictionary at all, it's probably not a DHT
355 diff --git a/src/download/download_info.h b/src/download/download_info.h
356 index 68fb178..2e27ba3 100644
357 --- a/src/download/download_info.h
358 +++ b/src/download/download_info.h
359 @@ -216,6 +216,28 @@ struct SocketAddressCompact {
360 const char* c_str() const { return reinterpret_cast<const char*>(this); }
361 } __attribute__ ((packed));
363 +#ifdef RAK_USE_INET6
364 +struct SocketAddressCompact6 {
365 + SocketAddressCompact6() {}
366 + SocketAddressCompact6(in6_addr a, uint16_t p) : addr(a), port(p) {}
367 + SocketAddressCompact6(const rak::socket_address_inet6* sa) : addr(sa->address()), port(sa->port_n()) {}
369 + operator rak::socket_address () const {
370 + rak::socket_address sa;
371 + sa.sa_inet6()->clear();
372 + sa.sa_inet6()->set_port_n(port);
373 + sa.sa_inet6()->set_address(addr);
381 + const char* c_str() const { return reinterpret_cast<const char*>(this); }
382 +} __attribute__ ((packed));
388 diff --git a/src/net/Makefile.am b/src/net/Makefile.am
389 index e07f382..3df0f6d 100644
390 --- a/src/net/Makefile.am
391 +++ b/src/net/Makefile.am
392 @@ -4,6 +4,8 @@ libsub_net_la_SOURCES = \
401 diff --git a/src/net/Makefile.in b/src/net/Makefile.in
402 index 1920403..cdbe398 100644
403 --- a/src/net/Makefile.in
404 +++ b/src/net/Makefile.in
405 @@ -54,9 +54,9 @@ CONFIG_CLEAN_FILES =
406 CONFIG_CLEAN_VPATH_FILES =
407 LTLIBRARIES = $(noinst_LTLIBRARIES)
408 libsub_net_la_LIBADD =
409 -am_libsub_net_la_OBJECTS = address_list.lo listen.lo socket_base.lo \
410 - socket_datagram.lo socket_fd.lo socket_set.lo socket_stream.lo \
411 - throttle_internal.lo throttle_list.lo
412 +am_libsub_net_la_OBJECTS = address_list.lo local_addr.lo listen.lo \
413 + socket_base.lo socket_datagram.lo socket_fd.lo socket_set.lo \
414 + socket_stream.lo throttle_internal.lo throttle_list.lo
415 libsub_net_la_OBJECTS = $(am_libsub_net_la_OBJECTS)
416 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
417 depcomp = $(SHELL) $(top_srcdir)/depcomp
418 @@ -216,6 +216,8 @@ libsub_net_la_SOURCES = \
427 @@ -290,6 +292,7 @@ distclean-compile:
429 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address_list.Plo@am__quote@
430 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Plo@am__quote@
431 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_addr.Plo@am__quote@
432 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_base.Plo@am__quote@
433 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_datagram.Plo@am__quote@
434 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_fd.Plo@am__quote@
435 diff --git a/src/net/address_list.cc b/src/net/address_list.cc
436 index e5cf3cb..68a0b22 100644
437 --- a/src/net/address_list.cc
438 +++ b/src/net/address_list.cc
439 @@ -70,16 +70,6 @@ AddressList::parse_address_normal(const Object::list_type& b) {
443 -AddressList::parse_address_compact(SimpleString s) {
444 - if (sizeof(const SocketAddressCompact) != 6)
445 - throw internal_error("ConnectionList::AddressList::parse_address_compact(...) bad struct size.");
447 - std::copy(reinterpret_cast<const SocketAddressCompact*>(s.c_str()),
448 - reinterpret_cast<const SocketAddressCompact*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact)),
449 - std::back_inserter(*this));
453 AddressList::parse_address_bencode(SimpleString s) {
454 if (sizeof(const SocketAddressCompact) != 6)
455 throw internal_error("AddressList::parse_address_bencode(...) bad struct size.");
456 @@ -93,4 +83,26 @@ AddressList::parse_address_bencode(SimpleString s) {
461 +AddressList::parse_address_compact(SimpleString s) {
462 + if (sizeof(const SocketAddressCompact) != 6)
463 + throw internal_error("ConnectionList::AddressList::parse_address_compact(...) bad struct size.");
465 + std::copy(reinterpret_cast<const SocketAddressCompact*>(s.c_str()),
466 + reinterpret_cast<const SocketAddressCompact*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact)),
467 + std::back_inserter(*this));
470 +#ifdef RAK_USE_INET6
472 +AddressList::parse_address_compact_ipv6(const std::string& s) {
473 + if (sizeof(const SocketAddressCompact6) != 18)
474 + throw internal_error("ConnectionList::AddressList::parse_address_compact_ipv6(...) bad struct size.");
476 + std::copy(reinterpret_cast<const SocketAddressCompact6*>(s.c_str()),
477 + reinterpret_cast<const SocketAddressCompact6*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact6)),
478 + std::back_inserter(*this));
483 diff --git a/src/net/address_list.h b/src/net/address_list.h
484 index 10dbac4..d264d95 100644
485 --- a/src/net/address_list.h
486 +++ b/src/net/address_list.h
487 @@ -50,8 +50,11 @@ class AddressList : public std::list<rak::socket_address> {
489 // Parse normal or compact list of addresses and add to AddressList
490 void parse_address_normal(const Object::list_type& b);
491 - void parse_address_compact(SimpleString s);
492 void parse_address_bencode(SimpleString s);
493 + void parse_address_compact(SimpleString s);
494 +#ifdef RAK_USE_INET6
495 + void parse_address_compact_ipv6(const std::string& s);
499 static rak::socket_address parse_address(const Object& b);
500 diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc
502 index 0000000..fae3f85
504 +++ b/src/net/local_addr.cc
506 +// libTorrent - BitTorrent library
507 +// Copyright (C) 2005-2007, Jari Sundell
509 +// This program is free software; you can redistribute it and/or modify
510 +// it under the terms of the GNU General Public License as published by
511 +// the Free Software Foundation; either version 2 of the License, or
512 +// (at your option) any later version.
514 +// This program is distributed in the hope that it will be useful,
515 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
516 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
517 +// GNU General Public License for more details.
519 +// You should have received a copy of the GNU General Public License
520 +// along with this program; if not, write to the Free Software
521 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
523 +// In addition, as a special exception, the copyright holders give
524 +// permission to link the code of portions of this program with the
525 +// OpenSSL library under certain conditions as described in each
526 +// individual source file, and distribute linked combinations
527 +// including the two.
529 +// You must obey the GNU General Public License in all respects for
530 +// all of the code used other than OpenSSL. If you modify file(s)
531 +// with this exception, you may extend this exception to your version
532 +// of the file(s), but you are not obligated to do so. If you do not
533 +// wish to do so, delete this exception statement from your version.
534 +// If you delete this exception statement from all source files in the
535 +// program, then also delete it here.
537 +// Contact: Jari Sundell <jaris@ifi.uio.no>
540 +// 3185 Skoppum, NORWAY
545 +#include <ifaddrs.h>
546 +#include <rak/socket_address.h>
547 +#include <sys/types.h>
551 +#include <linux/netlink.h>
552 +#include <linux/rtnetlink.h>
555 +#include "torrent/exceptions.h"
556 +#include "socket_fd.h"
557 +#include "local_addr.h"
562 +// IPv4 priority, from highest to lowest:
564 +// 1. Everything else (global address)
565 +// 2. Private address space (10.0.0.0/8, 172.16.0.0/16, 192.168.0.0/24)
566 +// 3. Empty/INADDR_ANY (0.0.0.0)
567 +// 4. Link-local address (169.254.0.0/16)
568 +// 5. Localhost (127.0.0.0/8)
569 +int get_priority_ipv4(const in_addr& addr) {
570 + if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x7f000000U)) {
573 + if (addr.s_addr == htonl(0)) {
576 + if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) {
579 + if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x0a000000U) ||
580 + (addr.s_addr & htonl(0xffff0000U)) == htonl(0xac100000U) ||
581 + (addr.s_addr & htonl(0xffff0000U)) == htonl(0xc0a80000U)) {
587 +#ifdef RAK_USE_INET6
588 +// IPv6 priority, from highest to lowest:
590 +// 1. Global address (2000::/16 not in 6to4 or Teredo)
591 +// 2. 6to4 (2002::/16)
592 +// 3. Teredo (2001::/32)
593 +// 4. Empty/INADDR_ANY (::)
594 +// 5. Everything else (link-local, ULA, etc.)
595 +int get_priority_ipv6(const in6_addr& addr) {
596 + const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(addr.s6_addr);
597 + if (addr32[0] == htonl(0) &&
598 + addr32[1] == htonl(0) &&
599 + addr32[2] == htonl(0) &&
600 + addr32[3] == htonl(0)) {
603 + if (addr32[0] == htonl(0x20010000)) {
606 + if ((addr32[0] & htonl(0xffff0000)) == htonl(0x20020000)) {
609 + if ((addr32[0] & htonl(0xe0000000)) == htonl(0x20000000)) {
616 +int get_priority(const rak::socket_address& addr) {
617 + switch (addr.family()) {
619 + return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr);
620 +#ifdef RAK_USE_INET6
622 + return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr);
625 + throw torrent::internal_error("Unknown address family given to compare");
633 +// Linux-specific implementation that understands how to filter away
634 +// understands how to filter away secondary addresses.
635 +bool get_local_address(sa_family_t family, rak::socket_address *address) {
637 + if (getifaddrs(&ifaddrs)) {
641 + rak::socket_address best_addr;
644 + best_addr.sa_inet()->clear();
646 +#ifdef RAK_USE_INET6
648 + best_addr.sa_inet6()->clear();
652 + throw torrent::internal_error("Unknown address family given to get_local_address");
655 + // The bottom bit of the priority is used to hold if the address is
656 + // a secondary address (e.g. with IPv6 privacy extensions) or not;
657 + // secondary addresses have lower priority (higher number).
658 + int best_addr_pri = get_priority(best_addr) * 2;
660 + // Get all the addresses via Linux' netlink interface.
661 + int fd = ::socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
666 + struct sockaddr_nl nladdr;
667 + memset(&nladdr, 0, sizeof(nladdr));
668 + nladdr.nl_family = AF_NETLINK;
669 + if (::bind(fd, (sockaddr *)&nladdr, sizeof(nladdr))) {
674 + const int seq_no = 1;
679 + memset(&req, 0, sizeof(req));
681 + req.nh.nlmsg_len = sizeof(req);
682 + req.nh.nlmsg_type = RTM_GETADDR;
683 + req.nh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
684 + req.nh.nlmsg_pid = getpid();
685 + req.nh.nlmsg_seq = seq_no;
686 + req.g.rtgen_family = AF_UNSPEC;
690 + ret = ::sendto(fd, &req, sizeof(req), 0, (sockaddr *)&nladdr, sizeof(nladdr));
691 + } while (ret == -1 && errno == EINTR);
701 + socklen_t len = sizeof(nladdr);
703 + ret = ::recvfrom(fd, buf, sizeof(buf), 0, (sockaddr *)&nladdr, &len);
704 + } while (ret == -1 && errno == EINTR);
711 + for (const nlmsghdr *nlmsg = (const nlmsghdr *)buf;
712 + NLMSG_OK(nlmsg, ret);
713 + nlmsg = NLMSG_NEXT(nlmsg, ret)) {
714 + if (nlmsg->nlmsg_seq != seq_no)
716 + if (nlmsg->nlmsg_type == NLMSG_DONE) {
720 + if (nlmsg->nlmsg_type == NLMSG_ERROR) {
724 + if (nlmsg->nlmsg_type != RTM_NEWADDR)
727 + const ifaddrmsg *ifa = (const ifaddrmsg *)NLMSG_DATA(nlmsg);
729 + if (ifa->ifa_family != family)
732 +#ifdef IFA_F_OPTIMISTIC
733 + if ((ifa->ifa_flags & IFA_F_OPTIMISTIC) != 0)
736 +#ifdef IFA_F_DADFAILED
737 + if ((ifa->ifa_flags & IFA_F_DADFAILED) != 0)
740 +#ifdef IFA_F_DEPRECATED
741 + if ((ifa->ifa_flags & IFA_F_DEPRECATED) != 0)
744 +#ifdef IFA_F_TENTATIVE
745 + if ((ifa->ifa_flags & IFA_F_TENTATIVE) != 0)
749 + // Since there can be point-to-point links on the machine, we need to keep
750 + // track of the addresses we've seen for this interface; if we see both
751 + // IFA_LOCAL and IFA_ADDRESS for an interface, keep only the IFA_LOCAL.
752 + rak::socket_address this_addr;
753 + bool seen_addr = false;
754 + int plen = IFA_PAYLOAD(nlmsg);
755 + for (const rtattr *rta = IFA_RTA(ifa);
757 + rta = RTA_NEXT(rta, plen)) {
758 + if (rta->rta_type != IFA_LOCAL &&
759 + rta->rta_type != IFA_ADDRESS) {
762 + if (rta->rta_type == IFA_ADDRESS && seen_addr) {
766 + switch (ifa->ifa_family) {
768 + this_addr.sa_inet()->clear();
769 + this_addr.sa_inet()->set_address(*(const in_addr *)RTA_DATA(rta));
771 +#ifdef RAK_USE_INET6
773 + this_addr.sa_inet6()->clear();
774 + this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta));
782 + int this_addr_pri = get_priority(this_addr) * 2;
783 + if ((ifa->ifa_flags & IFA_F_SECONDARY) == IFA_F_SECONDARY) {
787 + if (this_addr_pri < best_addr_pri) {
788 + best_addr = this_addr;
789 + best_addr_pri = this_addr_pri;
795 + if (!best_addr.is_address_any()) {
796 + *address = best_addr;
805 +// Generic POSIX variant.
806 +bool get_local_address(sa_family_t family, rak::socket_address *address) {
808 + if (!sock.open_datagram()) {
812 + rak::socket_address dummy_dest;
813 + dummy_dest.clear();
816 + case rak::socket_address::af_inet:
817 + dummy_dest.set_address_c_str("4.0.0.0");
819 +#ifdef RAK_USE_INET6
820 + case rak::socket_address::af_inet6:
821 + dummy_dest.set_address_c_str("2001:700::");
825 + throw internal_error("Unknown address family");
827 + dummy_dest.set_port(80);
829 + if (!sock.connect(dummy_dest)) {
834 + bool ret = sock.getsockname(address);
842 diff --git a/src/net/local_addr.h b/src/net/local_addr.h
844 index 0000000..43bc820
846 +++ b/src/net/local_addr.h
848 +// libTorrent - BitTorrent library
849 +// Copyright (C) 2005-2007, Jari Sundell
851 +// This program is free software; you can redistribute it and/or modify
852 +// it under the terms of the GNU General Public License as published by
853 +// the Free Software Foundation; either version 2 of the License, or
854 +// (at your option) any later version.
856 +// This program is distributed in the hope that it will be useful,
857 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
858 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
859 +// GNU General Public License for more details.
861 +// You should have received a copy of the GNU General Public License
862 +// along with this program; if not, write to the Free Software
863 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
865 +// In addition, as a special exception, the copyright holders give
866 +// permission to link the code of portions of this program with the
867 +// OpenSSL library under certain conditions as described in each
868 +// individual source file, and distribute linked combinations
869 +// including the two.
871 +// You must obey the GNU General Public License in all respects for
872 +// all of the code used other than OpenSSL. If you modify file(s)
873 +// with this exception, you may extend this exception to your version
874 +// of the file(s), but you are not obligated to do so. If you do not
875 +// wish to do so, delete this exception statement from your version.
876 +// If you delete this exception statement from all source files in the
877 +// program, then also delete it here.
879 +// Contact: Jari Sundell <jaris@ifi.uio.no>
882 +// 3185 Skoppum, NORWAY
884 +// A routine to get a local IP address that can be presented to a tracker.
885 +// (Does not use UPnP etc., so will not understand NAT.)
886 +// On a machine with multiple network cards, address selection can be a
887 +// complex process, and in general what's selected is a source/destination
888 +// address pair. However, this routine will give an approximation that will
889 +// be good enough for most purposes and users.
891 +#ifndef LIBTORRENT_NET_LOCAL_ADDR_H
892 +#define LIBTORRENT_NET_LOCAL_ADDR_H
897 + class socket_address;
902 +// Note: family must currently be rak::af_inet or rak::af_inet6
903 +// (rak::af_unspec won't do); anything else will throw an exception.
904 +// Returns false if no address of the given family could be found,
905 +// either because there are none, or because something went wrong in
906 +// the process (e.g., no free file descriptors).
907 +bool get_local_address(sa_family_t family, rak::socket_address *address);
911 +#endif /* LIBTORRENT_NET_LOCAL_ADDR_H */
912 diff --git a/src/net/socket_datagram.cc b/src/net/socket_datagram.cc
913 index b983289..69992e3 100644
914 --- a/src/net/socket_datagram.cc
915 +++ b/src/net/socket_datagram.cc
916 @@ -73,7 +73,13 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc
920 - r = ::sendto(m_fileDesc, buffer, length, 0, sa->sa_inet()->c_sockaddr(), sizeof(rak::socket_address_inet));
921 +#ifdef RAK_USE_INET6
922 + if (m_ipv6_socket && sa->family() == rak::socket_address::pf_inet) {
923 + rak::socket_address_inet6 sa_mapped = sa->sa_inet()->to_mapped_address();
924 + r = ::sendto(m_fileDesc, buffer, length, 0, sa_mapped.c_sockaddr(), sizeof(rak::socket_address_inet6));
927 + r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length());
929 r = ::send(m_fileDesc, buffer, length, 0);
931 diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc
932 index c349d21..20e2403 100644
933 --- a/src/net/socket_fd.cc
934 +++ b/src/net/socket_fd.cc
935 @@ -70,6 +70,11 @@ SocketFd::set_priority(priority_type p) {
939 +#ifdef RAK_USE_INET6
941 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
944 return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
947 @@ -112,12 +117,36 @@ SocketFd::get_error() const {
950 SocketFd::open_stream() {
951 +#ifdef RAK_USE_INET6
952 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
954 + m_ipv6_socket = false;
955 + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
957 + m_ipv6_socket = true;
960 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
962 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
967 SocketFd::open_datagram() {
968 +#ifdef RAK_USE_INET6
969 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
971 + m_ipv6_socket = false;
972 + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
974 + m_ipv6_socket = true;
977 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
979 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
984 @@ -135,6 +164,12 @@ bool
985 SocketFd::bind(const rak::socket_address& sa) {
988 +#ifdef RAK_USE_INET6
989 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
990 + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
991 + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
994 return !::bind(m_fd, sa.c_sockaddr(), sa.length());
997 @@ -142,6 +177,12 @@ bool
998 SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
1001 +#ifdef RAK_USE_INET6
1002 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
1003 + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
1004 + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
1007 return !::bind(m_fd, sa.c_sockaddr(), length);
1010 @@ -149,10 +190,34 @@ bool
1011 SocketFd::connect(const rak::socket_address& sa) {
1014 +#ifdef RAK_USE_INET6
1015 + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
1016 + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
1017 + return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
1020 return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
1024 +SocketFd::getsockname(rak::socket_address *sa) {
1027 + socklen_t len = sizeof(rak::socket_address);
1028 + if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
1032 +#ifdef RAK_USE_INET6
1033 + if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
1034 + *sa = sa->sa_inet6()->normalize_address();
1042 SocketFd::listen(int size) {
1045 @@ -164,7 +229,18 @@ SocketFd::accept(rak::socket_address* sa) {
1047 socklen_t len = sizeof(rak::socket_address);
1049 +#ifdef RAK_USE_INET6
1051 + return SocketFd(::accept(m_fd, NULL, &len));
1053 + int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
1054 + if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
1055 + *sa = sa->sa_inet6()->normalize_address();
1057 + return SocketFd(fd);
1059 return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
1064 diff --git a/src/net/socket_fd.h b/src/net/socket_fd.h
1065 index a208ad6..d39c413 100644
1066 --- a/src/net/socket_fd.h
1067 +++ b/src/net/socket_fd.h
1068 @@ -77,6 +77,7 @@ public:
1069 bool bind(const rak::socket_address& sa);
1070 bool bind(const rak::socket_address& sa, unsigned int length);
1071 bool connect(const rak::socket_address& sa);
1072 + bool getsockname(rak::socket_address* sa);
1074 bool listen(int size);
1075 SocketFd accept(rak::socket_address* sa);
1076 @@ -88,6 +89,9 @@ private:
1077 inline void check_valid() const;
1080 +#ifdef RAK_USE_INET6
1081 + bool m_ipv6_socket;
1086 diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc
1087 index 64c4197..152a0a1 100644
1088 --- a/src/torrent/connection_manager.cc
1089 +++ b/src/torrent/connection_manager.cc
1090 @@ -78,13 +78,18 @@ ConnectionManager::ConnectionManager() :
1091 m_slotResolver(&resolve_host) {
1093 m_bindAddress = (new rak::socket_address())->c_sockaddr();
1094 - rak::socket_address::cast_from(m_bindAddress)->sa_inet()->clear();
1096 m_localAddress = (new rak::socket_address())->c_sockaddr();
1097 - rak::socket_address::cast_from(m_localAddress)->sa_inet()->clear();
1099 m_proxyAddress = (new rak::socket_address())->c_sockaddr();
1101 +#ifdef RAK_USE_INET6
1102 + rak::socket_address::cast_from(m_bindAddress)->sa_inet6()->clear();
1103 + rak::socket_address::cast_from(m_localAddress)->sa_inet6()->clear();
1104 + rak::socket_address::cast_from(m_proxyAddress)->sa_inet6()->clear();
1106 + rak::socket_address::cast_from(m_bindAddress)->sa_inet()->clear();
1107 + rak::socket_address::cast_from(m_localAddress)->sa_inet()->clear();
1108 rak::socket_address::cast_from(m_proxyAddress)->sa_inet()->clear();
1112 ConnectionManager::~ConnectionManager() {
1113 @@ -123,8 +128,10 @@ void
1114 ConnectionManager::set_bind_address(const sockaddr* sa) {
1115 const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
1117 +#ifndef RAK_USE_INET6
1118 if (rsa->family() != rak::socket_address::af_inet)
1119 throw input_error("Tried to set a bind address that is not an af_inet address.");
1122 rak::socket_address::cast_from(m_bindAddress)->copy(*rsa, rsa->length());
1124 @@ -133,8 +140,10 @@ void
1125 ConnectionManager::set_local_address(const sockaddr* sa) {
1126 const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
1128 +#ifndef RAK_USE_INET6
1129 if (rsa->family() != rak::socket_address::af_inet)
1130 throw input_error("Tried to set a local address that is not an af_inet address.");
1133 rak::socket_address::cast_from(m_localAddress)->copy(*rsa, rsa->length());
1135 @@ -143,8 +152,10 @@ void
1136 ConnectionManager::set_proxy_address(const sockaddr* sa) {
1137 const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
1139 +#ifndef RAK_USE_INET6
1140 if (rsa->family() != rak::socket_address::af_inet)
1141 throw input_error("Tried to set a proxy address that is not an af_inet address.");
1144 rak::socket_address::cast_from(m_proxyAddress)->copy(*rsa, rsa->length());
1146 diff --git a/src/torrent/event.h b/src/torrent/event.h
1147 index 335e6d6..2d6e36c 100644
1148 --- a/src/torrent/event.h
1149 +++ b/src/torrent/event.h
1150 @@ -57,6 +57,10 @@ public:
1155 +#ifdef RAK_USE_INET6
1156 + bool m_ipv6_socket;
1161 diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc
1162 index 187ba5b..cef840b 100644
1163 --- a/src/torrent/peer/peer_list.cc
1164 +++ b/src/torrent/peer/peer_list.cc
1165 @@ -65,15 +65,23 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) {
1167 return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
1169 +#ifdef RAK_USE_INET6
1171 + const in6_addr addr1 = sa1->sa_inet6()->address();
1172 + const in6_addr addr2 = sa2->sa_inet6()->address();
1173 + return memcmp(&addr1, &addr2, sizeof(in6_addr)) < 0;
1177 - // When we implement INET6 handling, embed the ipv4 address in
1178 - // the ipv6 address.
1179 throw internal_error("socket_address_key(...) tried to compare an invalid family type.");
1185 socket_address_key::is_comparable(const sockaddr* sa) {
1186 - return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet;
1187 + return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet ||
1188 + rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6;
1191 struct peer_list_equal_port : public std::binary_function<PeerList::reference, uint16_t, bool> {
1192 diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
1193 index d23cae6..493dd0d 100644
1194 --- a/src/tracker/tracker_http.cc
1195 +++ b/src/tracker/tracker_http.cc
1198 #include "download/download_info.h"
1199 #include "net/address_list.h"
1200 +#include "net/local_addr.h"
1201 #include "torrent/connection_manager.h"
1202 #include "torrent/exceptions.h"
1203 #include "torrent/http.h"
1204 @@ -114,9 +115,16 @@ TrackerHttp::send_state(int state) {
1206 const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
1208 - if (localAddress->family() == rak::socket_address::af_inet &&
1209 - !localAddress->sa_inet()->is_address_any())
1210 + if (!localAddress->is_address_any())
1211 s << "&ip=" << localAddress->address_str();
1213 +#ifdef RAK_USE_INET6
1214 + if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet6) {
1215 + rak::socket_address local_v6;
1216 + if (get_local_address(rak::socket_address::af_inet6, &local_v6))
1217 + s << "&ipv6=" << rak::copy_escape_html(local_v6.address_str());
1221 if (info->is_compact())
1223 @@ -220,18 +228,34 @@ TrackerHttp::receive_done() {
1228 - // Due to some trackers sending the wrong type when no peers are
1229 - // available, don't bork on it.
1230 - if (b.get_key("peers").is_string())
1231 - l.parse_address_compact(b.get_key_string("peers"));
1232 + if (!b.has_key("peers")
1233 +#ifdef RAK_USE_INET6
1234 + && !b.has_key("peers6")
1237 + return receive_failed("No peers returned");
1240 + if (b.has_key("peers")) {
1242 + // Due to some trackers sending the wrong type when no peers are
1243 + // available, don't bork on it.
1244 + if (b.get_key("peers").is_string())
1245 + l.parse_address_compact(b.get_key_string("peers"));
1247 + else if (b.get_key("peers").is_list())
1248 + l.parse_address_normal(b.get_key_list("peers"));
1250 - else if (b.get_key("peers").is_list())
1251 - l.parse_address_normal(b.get_key_list("peers"));
1252 + } catch (bencode_error& e) {
1253 + return receive_failed(e.what());
1257 - } catch (bencode_error& e) {
1258 - return receive_failed(e.what());
1259 +#ifdef RAK_USE_INET6
1260 + if (b.has_key("peers6")) {
1261 + l.parse_address_compact_ipv6(b.get_key_string("peers6"));
1266 m_parent->receive_success(this, &l);
1267 diff --git a/src/tracker/tracker_udp.cc b/src/tracker/tracker_udp.cc
1268 index dacf21b..63442a3 100644
1269 --- a/src/tracker/tracker_udp.cc
1270 +++ b/src/tracker/tracker_udp.cc
1271 @@ -271,11 +271,18 @@ TrackerUdp::prepare_announce_input() {
1273 const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
1275 - // This code assumes we're have a inet address.
1276 +#ifdef RAK_USE_INET6
1277 + uint32_t local_addr = 0;
1278 + if (localAddress->family() == rak::socket_address::af_inet)
1279 + local_addr = localAddress->sa_inet()->address_n();
1281 if (localAddress->family() != rak::socket_address::af_inet)
1282 throw internal_error("TrackerUdp::prepare_announce_input() info->local_address() not of family AF_INET.");
1284 + uint32_t local_addr = localAddress->sa_inet()->address_n();
1287 - m_writeBuffer->write_32_n(localAddress->sa_inet()->address_n());
1288 + m_writeBuffer->write_32_n(local_addr);
1289 m_writeBuffer->write_32(m_parent->key());
1290 m_writeBuffer->write_32(m_parent->numwant());
1291 m_writeBuffer->write_16(manager->connection_manager()->listen_port());