diff -Nur rtorrent-0.8.6.orig/rak/socket_address.h rtorrent-0.8.6/rak/socket_address.h
--- rtorrent-0.8.6.orig/rak/socket_address.h	2009-11-12 09:03:48.000000000 +0100
+++ rtorrent-0.8.6/rak/socket_address.h	2009-12-30 00:41:45.000000000 +0100
@@ -145,7 +145,7 @@
   };
 };
 
-// Remeber to set the AF_INET.
+// Remember to set the AF_INET.
 
 class socket_address_inet {
 public:
@@ -192,6 +192,52 @@
   struct sockaddr_in  m_sockaddr;
 };
 
+#ifdef RAK_USE_INET6
+// Remember to set the AF_INET6.
+
+class socket_address_inet6 {
+public:
+  bool                is_any() const                          { return is_port_any() && is_address_any(); }
+  bool                is_valid() const                        { return !is_port_any() && !is_address_any(); }
+  bool                is_port_any() const                     { return port() == 0; }
+  bool                is_address_any() const                  { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
+
+  void                clear()                                 { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
+
+  uint16_t            port() const                            { return ntohs(m_sockaddr.sin6_port); }
+  uint16_t            port_n() const                          { return m_sockaddr.sin6_port; }
+  void                set_port(uint16_t p)                    { m_sockaddr.sin6_port = htons(p); }
+  void                set_port_n(uint16_t p)                  { m_sockaddr.sin6_port = p; }
+
+  in6_addr            address() const                         { return m_sockaddr.sin6_addr; }
+  std::string         address_str() const;
+  bool                address_c_str(char* buf, socklen_t size) const;
+
+  void                set_address(in6_addr a)                 { m_sockaddr.sin6_addr = a; }
+  bool                set_address_str(const std::string& a)   { return set_address_c_str(a.c_str()); }
+  bool                set_address_c_str(const char* a);
+
+  void                set_address_any()                       { set_port(0); set_address(in6addr_any); }
+
+  sa_family_t         family() const                          { return m_sockaddr.sin6_family; }
+  void                set_family()                            { m_sockaddr.sin6_family = AF_INET6; }
+
+  sockaddr*           c_sockaddr()                            { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
+  sockaddr_in6*       c_sockaddr_inet6()                      { return &m_sockaddr; }
+
+  const sockaddr*     c_sockaddr() const                      { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
+  const sockaddr_in6* c_sockaddr_inet6() const                { return &m_sockaddr; }
+
+  socket_address      normalize_address() const;
+
+  bool                operator == (const socket_address_inet6& rhs) const;
+  bool                operator < (const socket_address_inet6& rhs) const;
+
+private:
+  struct sockaddr_in6 m_sockaddr;
+};
+#endif
+
 // Unique key for the address, excluding port numbers etc.
 class socket_address_key {
 public:
@@ -241,8 +287,10 @@
   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 +301,10 @@
   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 +315,10 @@
   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 +329,10 @@
   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 +343,10 @@
   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 +357,10 @@
   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 +371,10 @@
   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 +386,10 @@
     sa_inet()->set_family();
     return true;
 
+  } else if (sa_inet6()->set_address_c_str(a)) {
+    sa_inet6()->set_family();
+    return true;
+
   } else {
     return false;
   }
@@ -325,6 +401,10 @@
   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 +429,10 @@
   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 +446,10 @@
   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.");
   }
@@ -406,6 +490,59 @@
      m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
 }
 
+#ifdef RAK_USE_INET6
+
+inline std::string
+socket_address_inet6::address_str() const {
+  char buf[INET6_ADDRSTRLEN];
+
+  if (!address_c_str(buf, INET6_ADDRSTRLEN))
+    return std::string();
+
+  return std::string(buf);
+}
+
+inline bool
+socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
+  return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
+}
+
+inline bool
+socket_address_inet6::set_address_c_str(const char* a) {
+  return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
+}
+
+inline socket_address
+socket_address_inet6::normalize_address() const {
+  const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
+  if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
+    socket_address addr4;
+    addr4.sa_inet()->set_family();
+    addr4.sa_inet()->set_address_n(addr32[3]);
+    addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
+    return addr4;
+  }
+  return *reinterpret_cast<const socket_address*>(this);
+}
+
+inline bool
+socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
+  return
+    memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
+    m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
+}
+
+inline bool
+socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
+  int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
+  return
+    addr_comp < 0 ||
+    (addr_comp == 0 ||
+     m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
+}
+
+#endif
+
 }
 
 #endif
diff -Nur rtorrent-0.8.6.orig/src/core/curl_get.cc rtorrent-0.8.6/src/core/curl_get.cc
--- rtorrent-0.8.6.orig/src/core/curl_get.cc	2009-11-12 09:03:44.000000000 +0100
+++ rtorrent-0.8.6/src/core/curl_get.cc	2009-12-27 02:35:39.000000000 +0100
@@ -88,8 +88,20 @@
   curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL,       (long)1);
   curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
   curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS,      (long)5);
+
+  // Even when IPv6-enabled, we don't want to use CURL_IPRESOLVE_WHATEVER,
+  // since that will usually prefer connecting over IPv6 to the tracker.
+  // Since it's usually a lot easier to find our global IPv6 address
+  // (if we have one) than our global IPv4 address, we prefer connecting
+  // over IPv4 if we can, so that the tracker will get our IPv4 address
+  // that way. If the resolve fails, CurlStack will call retry_ipv6()
+  // on us and we'll make a second attempt with CURL_IPRESOLVE_V6.
   curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE,      CURL_IPRESOLVE_V4);
+
   curl_easy_setopt(m_handle, CURLOPT_ENCODING,       "");
+#ifdef RAK_USE_INET6
+  m_ipv6 = false;
+#endif
 
   m_stack->add_get(this);
 }
@@ -107,6 +119,17 @@
   m_handle = NULL;
 }
 
+#ifdef RAK_USE_INET6
+void
+CurlGet::retry_ipv6() {
+  CURL* nhandle = curl_easy_duphandle(m_handle);
+  curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
+  curl_easy_cleanup(m_handle);
+  m_handle = nhandle;
+  m_ipv6 = true;
+}
+#endif
+
 void
 CurlGet::receive_timeout() {
   return m_stack->transfer_done(m_handle, "Timed out");
diff -Nur rtorrent-0.8.6.orig/src/core/curl_get.h rtorrent-0.8.6/src/core/curl_get.h
--- rtorrent-0.8.6.orig/src/core/curl_get.h	2009-11-12 09:03:44.000000000 +0100
+++ rtorrent-0.8.6/src/core/curl_get.h	2009-12-27 02:34:44.000000000 +0100
@@ -56,6 +56,10 @@
 
   void               start();
   void               close();
+#ifdef RAK_USE_INET6
+  bool               is_using_ipv6()    { return m_ipv6; }
+  void               retry_ipv6();
+#endif
 
   bool               is_busy() const    { return m_handle; }
   bool               is_active() const  { return m_active; }
@@ -74,6 +78,9 @@
   void               receive_timeout();
 
   bool               m_active;
+#ifdef RAK_USE_INET6
+  bool               m_ipv6;
+#endif
 
   rak::priority_item m_taskTimeout;
   
diff -Nur rtorrent-0.8.6.orig/src/core/curl_stack.cc rtorrent-0.8.6/src/core/curl_stack.cc
--- rtorrent-0.8.6.orig/src/core/curl_stack.cc	2009-11-12 09:03:44.000000000 +0100
+++ rtorrent-0.8.6/src/core/curl_stack.cc	2009-12-26 16:03:36.000000000 +0100
@@ -111,6 +111,21 @@
         if (msg->msg != CURLMSG_DONE)
           throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
 
+#ifdef RAK_USE_INET6
+        if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
+          iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
+
+          if (itr == end())
+            throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
+
+          if (!(*itr)->is_using_ipv6()) {
+            (*itr)->retry_ipv6();
+            if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
+              throw torrent::internal_error("Error calling curl_multi_add_handle.");
+            continue;
+          }
+        } else
+#endif
 	transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
       }
 
diff -Nur rtorrent-0.8.6.orig/src/display/window_peer_list.cc rtorrent-0.8.6/src/display/window_peer_list.cc
--- rtorrent-0.8.6.orig/src/display/window_peer_list.cc	2009-11-12 09:03:47.000000000 +0100
+++ rtorrent-0.8.6/src/display/window_peer_list.cc	2009-12-26 00:48:03.000000000 +0100
@@ -68,7 +68,11 @@
   int x = 2;
   int y = 0;
 
-  m_canvas->print(x, y, "IP");     x += 16;
+#ifdef RAK_USE_INET6
+  m_canvas->print(x, y, "IP");      x += 25;
+#else
+  m_canvas->print(x, y, "IP");      x += 16;
+#endif
   m_canvas->print(x, y, "UP");      x += 7;
   m_canvas->print(x, y, "DOWN");    x += 7;
   m_canvas->print(x, y, "PEER");    x += 7;
@@ -99,10 +103,21 @@
 
     x = 0;
 
+    std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
+#ifdef RAK_USE_INET6
+    if (ip_address.size() >= 24) {
+      ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
+    }
+#endif
+
     m_canvas->print(x, y, "%c %s",
                     range.first == *m_focus ? '*' : ' ',
-                    rak::socket_address::cast_from(p->address())->address_str().c_str());
+                    ip_address.c_str());
+#ifdef RAK_USE_INET6
+    x += 27;
+#else
     x += 18;
+#endif
 
     m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7;
     m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7;
Binary files rtorrent-0.8.6.orig/src/rtorrent.db and rtorrent-0.8.6/src/rtorrent.db differ
Binary files rtorrent-0.8.6.orig/ubuntu-9.10-desktop-i386.ipv6.iso and rtorrent-0.8.6/ubuntu-9.10-desktop-i386.ipv6.iso differ
Binary files rtorrent-0.8.6.orig/ubuntu-9.10-desktop-i386.ipv6.iso.torrent?83D904AE21339AE6551D231BB57178E3B4C329DB and rtorrent-0.8.6/ubuntu-9.10-desktop-i386.ipv6.iso.torrent?83D904AE21339AE6551D231BB57178E3B4C329DB differ
