updated on Tue Jan 10 00:10:07 UTC 2012
[aur-mirror.git] / libtorrent-extended / ex_ipv6.patch
blob2cff3e0d8f84487f4cd6dba93489e511eb297caa
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:
6 };
7 };
9 -// Remeber to set the AF_INET.
10 +// Remember to set the AF_INET.
12 class socket_address_inet {
13 public:
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; }
19 +#ifdef RAK_USE_INET6
20 + socket_address_inet6 to_mapped_address() const;
21 +#endif
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;
29 +#ifdef RAK_USE_INET6
30 +// Remember to set the AF_INET6.
32 +class socket_address_inet6 {
33 +public:
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;
70 +private:
71 + struct sockaddr_in6 m_sockaddr;
72 +};
73 +#endif
75 // Unique key for the address, excluding port numbers etc.
76 class socket_address_key {
77 public:
78 @@ -241,8 +291,10 @@ socket_address::is_valid() const {
79 switch (family()) {
80 case af_inet:
81 return sa_inet()->is_valid();
82 -// case af_inet6:
83 -// return sa_inet6().is_valid();
84 +#ifdef RAK_USE_INET6
85 + case af_inet6:
86 + return sa_inet6()->is_valid();
87 +#endif
88 default:
89 return false;
91 @@ -253,6 +305,10 @@ socket_address::is_bindable() const {
92 switch (family()) {
93 case af_inet:
94 return !sa_inet()->is_address_any();
95 +#ifdef RAK_USE_INET6
96 + case af_inet6:
97 + return !sa_inet6()->is_address_any();
98 +#endif
99 default:
100 return false;
102 @@ -263,6 +319,10 @@ socket_address::is_address_any() const {
103 switch (family()) {
104 case af_inet:
105 return sa_inet()->is_address_any();
106 +#ifdef RAK_USE_INET6
107 + case af_inet6:
108 + return sa_inet6()->is_address_any();
109 +#endif
110 default:
111 return true;
113 @@ -273,6 +333,10 @@ socket_address::port() const {
114 switch (family()) {
115 case af_inet:
116 return sa_inet()->port();
117 +#ifdef RAK_USE_INET6
118 + case af_inet6:
119 + return sa_inet6()->port();
120 +#endif
121 default:
122 return 0;
124 @@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) {
125 switch (family()) {
126 case af_inet:
127 return sa_inet()->set_port(p);
128 +#ifdef RAK_USE_INET6
129 + case af_inet6:
130 + return sa_inet6()->set_port(p);
131 +#endif
132 default:
133 break;
135 @@ -293,6 +361,10 @@ socket_address::address_str() const {
136 switch (family()) {
137 case af_inet:
138 return sa_inet()->address_str();
139 +#ifdef RAK_USE_INET6
140 + case af_inet6:
141 + return sa_inet6()->address_str();
142 +#endif
143 default:
144 return std::string();
146 @@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
147 switch (family()) {
148 case af_inet:
149 return sa_inet()->address_c_str(buf, size);
150 +#ifdef RAK_USE_INET6
151 + case af_inet6:
152 + return sa_inet6()->address_c_str(buf, size);
153 +#endif
154 default:
155 return false;
157 @@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) {
158 sa_inet()->set_family();
159 return true;
161 +#ifdef RAK_USE_INET6
162 + } else if (sa_inet6()->set_address_c_str(a)) {
163 + sa_inet6()->set_family();
164 + return true;
165 +#endif
167 } else {
168 return false;
170 @@ -325,6 +407,10 @@ socket_address::length() const {
171 switch(family()) {
172 case af_inet:
173 return sizeof(sockaddr_in);
174 +#ifdef RAK_USE_INET6
175 + case af_inet6:
176 + return sizeof(sockaddr_in6);
177 +#endif
178 default:
179 return 0;
181 @@ -349,8 +435,10 @@ socket_address::operator == (const socket_address& rhs) const {
182 switch (family()) {
183 case af_inet:
184 return *sa_inet() == *rhs.sa_inet();
185 -// case af_inet6:
186 -// return *sa_inet6() == *rhs.sa_inet6();
187 +#ifdef RAK_USE_INET6
188 + case af_inet6:
189 + return *sa_inet6() == *rhs.sa_inet6();
190 +#endif
191 default:
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 {
195 switch (family()) {
196 case af_inet:
197 return *sa_inet() < *rhs.sa_inet();
198 -// case af_inet6:
199 -// return *sa_inet6() < *rhs.sa_inet6();
200 +#ifdef RAK_USE_INET6
201 + case af_inet6:
202 + return *sa_inet6() < *rhs.sa_inet6();
203 +#endif
204 default:
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];
215 + addr32[0] = 0;
216 + addr32[1] = 0;
217 + addr32[2] = htonl(0xffff);
218 + addr32[3] = m_sockaddr.sin_addr.s_addr;
220 + socket_address_inet6 sa;
221 + sa.clear();
222 + sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
223 + sa.set_port_n(m_sockaddr.sin_port);
224 + return sa;
226 +#endif
228 inline bool
229 socket_address_inet::operator == (const socket_address_inet& rhs) const {
230 return
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
237 +inline std::string
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);
247 +inline bool
248 +socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
249 + return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
252 +inline bool
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);
265 + return addr4;
267 + return *reinterpret_cast<const socket_address*>(this);
270 +inline bool
271 +socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
272 + return
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;
277 +inline bool
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));
280 + return
281 + addr_comp < 0 ||
282 + (addr_comp == 0 ||
283 + m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
286 +#endif
290 #endif
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),
297 m_bucket(NULL) {
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");
304 +#else
305 if (sa->family() != rak::socket_address::af_inet)
306 throw resource_error("Address not af_inet");
307 +#endif
310 DhtNode::DhtNode(const SimpleString& id, const Object& cache) :
311 @@ -85,8 +92,20 @@ DhtNode::store_compact(char* buffer) const {
313 Object*
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());
325 + } else
326 +#endif
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);
332 return container;
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() {
339 if (read < 0)
340 break;
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();
347 +#endif
349 + if (sa.family() != rak::socket_address::af_inet)
350 + continue;
352 total += read;
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);
375 + return sa;
378 + in6_addr addr;
379 + uint16_t port;
381 + const char* c_str() const { return reinterpret_cast<const char*>(this); }
382 +} __attribute__ ((packed));
383 +#endif
387 #endif
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 = \
393 address_list.cc \
394 address_list.h \
395 data_buffer.h \
396 + local_addr.cc \
397 + local_addr.h \
398 listen.cc \
399 listen.h \
400 protocol_buffer.h \
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 = \
419 address_list.cc \
420 address_list.h \
421 data_buffer.h \
422 + local_addr.cc \
423 + local_addr.h \
424 listen.cc \
425 listen.h \
426 protocol_buffer.h \
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) {
442 void
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));
452 -void
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) {
460 +void
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
471 +void
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));
480 +#endif
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> {
488 public:
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);
496 +#endif
498 private:
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
501 new file mode 100644
502 index 0000000..fae3f85
503 --- /dev/null
504 +++ b/src/net/local_addr.cc
505 @@ -0,0 +1,336 @@
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.
513 +//
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.
518 +//
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>
539 +// Skomakerveien 33
540 +// 3185 Skoppum, NORWAY
542 +#include "config.h"
544 +#include <stdio.h>
545 +#include <ifaddrs.h>
546 +#include <rak/socket_address.h>
547 +#include <sys/types.h>
548 +#include <errno.h>
550 +#ifdef __linux__
551 +#include <linux/netlink.h>
552 +#include <linux/rtnetlink.h>
553 +#endif
555 +#include "torrent/exceptions.h"
556 +#include "socket_fd.h"
557 +#include "local_addr.h"
559 +namespace torrent {
560 +namespace {
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)) {
571 + return 5;
573 + if (addr.s_addr == htonl(0)) {
574 + return 4;
576 + if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) {
577 + return 3;
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)) {
582 + return 2;
584 + return 1;
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)) {
601 + return 4;
603 + if (addr32[0] == htonl(0x20010000)) {
604 + return 3;
606 + if ((addr32[0] & htonl(0xffff0000)) == htonl(0x20020000)) {
607 + return 2;
609 + if ((addr32[0] & htonl(0xe0000000)) == htonl(0x20000000)) {
610 + return 1;
612 + return 5;
614 +#endif
616 +int get_priority(const rak::socket_address& addr) {
617 + switch (addr.family()) {
618 + case AF_INET:
619 + return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr);
620 +#ifdef RAK_USE_INET6
621 + case AF_INET6:
622 + return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr);
623 +#endif
624 + default:
625 + throw torrent::internal_error("Unknown address family given to compare");
631 +#ifdef __linux__
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) {
636 + ifaddrs *ifaddrs;
637 + if (getifaddrs(&ifaddrs)) {
638 + return false;
641 + rak::socket_address best_addr;
642 + switch (family) {
643 + case AF_INET:
644 + best_addr.sa_inet()->clear();
645 + break;
646 +#ifdef RAK_USE_INET6
647 + case AF_INET6:
648 + best_addr.sa_inet6()->clear();
649 + break;
650 +#endif
651 + default:
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);
662 + if (fd == -1) {
663 + return false;
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))) {
670 + ::close(fd);
671 + return false;
674 + const int seq_no = 1;
675 + struct {
676 + nlmsghdr nh;
677 + rtgenmsg g;
678 + } req;
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;
688 + int ret;
689 + do {
690 + ret = ::sendto(fd, &req, sizeof(req), 0, (sockaddr *)&nladdr, sizeof(nladdr));
691 + } while (ret == -1 && errno == EINTR);
693 + if (ret == -1) {
694 + ::close(fd);
695 + return false;
698 + bool done = false;
699 + do {
700 + char buf[4096];
701 + socklen_t len = sizeof(nladdr);
702 + do {
703 + ret = ::recvfrom(fd, buf, sizeof(buf), 0, (sockaddr *)&nladdr, &len);
704 + } while (ret == -1 && errno == EINTR);
706 + if (ret < 0) {
707 + ::close(fd);
708 + return false;
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)
715 + continue;
716 + if (nlmsg->nlmsg_type == NLMSG_DONE) {
717 + done = true;
718 + break;
720 + if (nlmsg->nlmsg_type == NLMSG_ERROR) {
721 + ::close(fd);
722 + return false;
724 + if (nlmsg->nlmsg_type != RTM_NEWADDR)
725 + continue;
727 + const ifaddrmsg *ifa = (const ifaddrmsg *)NLMSG_DATA(nlmsg);
729 + if (ifa->ifa_family != family)
730 + continue;
732 +#ifdef IFA_F_OPTIMISTIC
733 + if ((ifa->ifa_flags & IFA_F_OPTIMISTIC) != 0)
734 + continue;
735 +#endif
736 +#ifdef IFA_F_DADFAILED
737 + if ((ifa->ifa_flags & IFA_F_DADFAILED) != 0)
738 + continue;
739 +#endif
740 +#ifdef IFA_F_DEPRECATED
741 + if ((ifa->ifa_flags & IFA_F_DEPRECATED) != 0)
742 + continue;
743 +#endif
744 +#ifdef IFA_F_TENTATIVE
745 + if ((ifa->ifa_flags & IFA_F_TENTATIVE) != 0)
746 + continue;
747 +#endif
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);
756 + RTA_OK(rta, plen);
757 + rta = RTA_NEXT(rta, plen)) {
758 + if (rta->rta_type != IFA_LOCAL &&
759 + rta->rta_type != IFA_ADDRESS) {
760 + continue;
762 + if (rta->rta_type == IFA_ADDRESS && seen_addr) {
763 + continue;
765 + seen_addr = true;
766 + switch (ifa->ifa_family) {
767 + case AF_INET:
768 + this_addr.sa_inet()->clear();
769 + this_addr.sa_inet()->set_address(*(const in_addr *)RTA_DATA(rta));
770 + break;
771 +#ifdef RAK_USE_INET6
772 + case AF_INET6:
773 + this_addr.sa_inet6()->clear();
774 + this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta));
775 + break;
776 +#endif
779 + if (!seen_addr)
780 + continue;
782 + int this_addr_pri = get_priority(this_addr) * 2;
783 + if ((ifa->ifa_flags & IFA_F_SECONDARY) == IFA_F_SECONDARY) {
784 + ++this_addr_pri;
787 + if (this_addr_pri < best_addr_pri) {
788 + best_addr = this_addr;
789 + best_addr_pri = this_addr_pri;
792 + } while (!done);
794 + ::close(fd);
795 + if (!best_addr.is_address_any()) {
796 + *address = best_addr;
797 + return true;
798 + } else {
799 + return false;
800 + }
803 +#else
805 +// Generic POSIX variant.
806 +bool get_local_address(sa_family_t family, rak::socket_address *address) {
807 + SocketFd sock;
808 + if (!sock.open_datagram()) {
809 + return false;
812 + rak::socket_address dummy_dest;
813 + dummy_dest.clear();
815 + switch (family) {
816 + case rak::socket_address::af_inet:
817 + dummy_dest.set_address_c_str("4.0.0.0");
818 + break;
819 +#ifdef RAK_USE_INET6
820 + case rak::socket_address::af_inet6:
821 + dummy_dest.set_address_c_str("2001:700::");
822 + break;
823 +#endif
824 + default:
825 + throw internal_error("Unknown address family");
827 + dummy_dest.set_port(80);
829 + if (!sock.connect(dummy_dest)) {
830 + sock.close();
831 + return false;
834 + bool ret = sock.getsockname(address);
835 + sock.close();
836 + return ret;
839 +#endif
842 diff --git a/src/net/local_addr.h b/src/net/local_addr.h
843 new file mode 100644
844 index 0000000..43bc820
845 --- /dev/null
846 +++ b/src/net/local_addr.h
847 @@ -0,0 +1,64 @@
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.
855 +//
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.
860 +//
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>
881 +// Skomakerveien 33
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
894 +#include <unistd.h>
896 +namespace rak {
897 + class socket_address;
900 +namespace torrent {
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
917 int r;
919 if (sa != NULL) {
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));
925 + } else
926 +#endif
927 + r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length());
928 } else {
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) {
936 check_valid();
937 int opt = p;
939 +#ifdef RAK_USE_INET6
940 + if (m_ipv6_socket)
941 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
942 + else
943 +#endif
944 return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
947 @@ -112,12 +117,36 @@ SocketFd::get_error() const {
949 bool
950 SocketFd::open_stream() {
951 +#ifdef RAK_USE_INET6
952 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
953 + if (m_fd == -1) {
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;
959 + int zero = 0;
960 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
961 +#else
962 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
963 +#endif
966 bool
967 SocketFd::open_datagram() {
968 +#ifdef RAK_USE_INET6
969 + m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
970 + if (m_fd == -1) {
971 + m_ipv6_socket = false;
972 + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
974 + m_ipv6_socket = true;
976 + int zero = 0;
977 + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
978 +#else
979 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
980 +#endif
983 bool
984 @@ -135,6 +164,12 @@ bool
985 SocketFd::bind(const rak::socket_address& sa) {
986 check_valid();
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));
993 +#endif
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) {
999 check_valid();
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));
1006 +#endif
1007 return !::bind(m_fd, sa.c_sockaddr(), length);
1010 @@ -149,10 +190,34 @@ bool
1011 SocketFd::connect(const rak::socket_address& sa) {
1012 check_valid();
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;
1019 +#endif
1020 return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
1023 bool
1024 +SocketFd::getsockname(rak::socket_address *sa) {
1025 + check_valid();
1027 + socklen_t len = sizeof(rak::socket_address);
1028 + if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
1029 + return false;
1032 +#ifdef RAK_USE_INET6
1033 + if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
1034 + *sa = sa->sa_inet6()->normalize_address();
1036 +#endif
1038 + return true;
1041 +bool
1042 SocketFd::listen(int size) {
1043 check_valid();
1045 @@ -164,7 +229,18 @@ SocketFd::accept(rak::socket_address* sa) {
1046 check_valid();
1047 socklen_t len = sizeof(rak::socket_address);
1049 +#ifdef RAK_USE_INET6
1050 + if (sa == NULL) {
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);
1058 +#else
1059 return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
1060 +#endif
1063 // unsigned int
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;
1079 int m_fd;
1080 +#ifdef RAK_USE_INET6
1081 + bool m_ipv6_socket;
1082 +#endif
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();
1105 +#else
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();
1109 +#endif
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.");
1120 +#endif
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.");
1131 +#endif
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.");
1142 +#endif
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:
1152 protected:
1153 int m_fileDesc;
1155 +#ifdef RAK_USE_INET6
1156 + bool m_ipv6_socket;
1157 +#endif
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) {
1166 // humans.
1167 return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
1169 +#ifdef RAK_USE_INET6
1170 + else {
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;
1175 +#else
1176 else
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.");
1180 +#endif
1184 inline bool
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
1196 @@ -43,6 +43,7 @@
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());
1219 +#endif
1221 if (info->is_compact())
1222 s << "&compact=1";
1223 @@ -220,18 +228,34 @@ TrackerHttp::receive_done() {
1225 AddressList l;
1227 - try {
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")
1235 +#endif
1236 + ) {
1237 + return receive_failed("No peers returned");
1240 + if (b.has_key("peers")) {
1241 + try {
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"));
1263 +#endif
1265 close();
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();
1280 +#else
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();
1285 +#endif
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());