libtorrent sync 1605

This commit is contained in:
Marcos Pinto 2007-09-24 23:07:45 +00:00
parent cf116cf3a1
commit 280eed95b6
19 changed files with 513 additions and 586 deletions

View File

@ -328,14 +328,33 @@ namespace libtorrent
struct TORRENT_EXPORT listen_failed_alert: alert struct TORRENT_EXPORT listen_failed_alert: alert
{ {
listen_failed_alert( listen_failed_alert(
const std::string& msg) tcp::endpoint const& ep
, std::string const& msg)
: alert(alert::fatal, msg) : alert(alert::fatal, msg)
, endpoint(ep)
{} {}
tcp::endpoint endpoint;
virtual std::auto_ptr<alert> clone() const virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new listen_failed_alert(*this)); } { return std::auto_ptr<alert>(new listen_failed_alert(*this)); }
}; };
struct TORRENT_EXPORT listen_succeeded_alert: alert
{
listen_succeeded_alert(
tcp::endpoint const& ep
, std::string const& msg)
: alert(alert::fatal, msg)
, endpoint(ep)
{}
tcp::endpoint endpoint;
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new listen_succeeded_alert(*this)); }
};
struct TORRENT_EXPORT portmap_error_alert: alert struct TORRENT_EXPORT portmap_error_alert: alert
{ {
portmap_error_alert(const std::string& msg) portmap_error_alert(const std::string& msg)

View File

@ -189,11 +189,16 @@ namespace libtorrent
#endif #endif
void operator()(); void operator()();
void open_listen_port(); void open_listen_port() throw();
void async_accept(); // if we are listening on an IPv6 interface
// this will return one of the IPv6 addresses on this
// machine, otherwise just an empty endpoint
tcp::endpoint get_ipv6_interface() const;
void async_accept(boost::shared_ptr<socket_acceptor> const& listener);
void on_incoming_connection(boost::shared_ptr<socket_type> const& s void on_incoming_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> const& as, asio::error_code const& e); , boost::weak_ptr<socket_acceptor> listener, asio::error_code const& e);
// must be locked to access the data // must be locked to access the data
// in this struct // in this struct
@ -393,8 +398,10 @@ namespace libtorrent
// at startup // at startup
int m_key; int m_key;
// the range of ports we try to listen on // the number of retries we make when binding the
std::pair<int, int> m_listen_port_range; // listen socket. For each retry the port number
// is incremented by one
int m_listen_port_retries;
// the ip-address of the interface // the ip-address of the interface
// we are supposed to listen on. // we are supposed to listen on.
@ -402,17 +409,32 @@ namespace libtorrent
// that we should let the os decide which // that we should let the os decide which
// interface to listen on // interface to listen on
tcp::endpoint m_listen_interface; tcp::endpoint m_listen_interface;
// this is typically set to the same as the local
// listen port. In case a NAT port forward was
// successfully opened, this will be set to the
// port that is open on the external (NAT) interface
// on the NAT box itself. This is the port that has
// to be published to peers, since this is the port
// the client is reachable through.
int m_external_listen_port;
boost::shared_ptr<socket_acceptor> m_listen_socket; // if we're listening on an IPv6 interface
// this is one of the non local IPv6 interfaces
// on this machine
tcp::endpoint m_ipv6_interface;
struct listen_socket_t
{
listen_socket_t(): external_port(0) {}
// this is typically set to the same as the local
// listen port. In case a NAT port forward was
// successfully opened, this will be set to the
// port that is open on the external (NAT) interface
// on the NAT box itself. This is the port that has
// to be published to peers, since this is the port
// the client is reachable through.
int external_port;
// the actual socket
boost::shared_ptr<socket_acceptor> sock;
};
// since we might be listening on multiple interfaces
// we might need more than one listen socket
std::list<listen_socket_t> m_listen_sockets;
listen_socket_t setup_listener(tcp::endpoint ep, int retries);
// the settings for the client // the settings for the client
session_settings m_settings; session_settings m_settings;

View File

@ -44,6 +44,7 @@ namespace libtorrent
bool is_local(address const& a); bool is_local(address const& a);
bool is_loopback(address const& addr); bool is_loopback(address const& addr);
bool is_multicast(address const& addr); bool is_multicast(address const& addr);
bool is_any(address const& addr);
address_v4 guess_local_address(asio::io_service&); address_v4 guess_local_address(asio::io_service&);

View File

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin Copyright (c) 2007, Arvid Norberg
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -32,9 +32,8 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef LIBTORRENT_BUFFER_HPP #ifndef LIBTORRENT_BUFFER_HPP
#define LIBTORRENT_BUFFER_HPP #define LIBTORRENT_BUFFER_HPP
//#define TORRENT_BUFFER_DEBUG
#include <memory> #include <memory>
#include <cstring>
#include "libtorrent/invariant_check.hpp" #include "libtorrent/invariant_check.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
@ -43,410 +42,157 @@ namespace libtorrent {
class buffer class buffer
{ {
public: public:
struct interval struct interval
{ {
interval(char* begin, char* end) interval(char* begin, char* end)
: begin(begin) : begin(begin)
, end(end) , end(end)
{} {}
char operator[](int index) const char operator[](int index) const
{ {
assert(begin + index < end); assert(begin + index < end);
return begin[index]; return begin[index];
} }
int left() const { assert(end >= begin); return end - begin; } int left() const { assert(end >= begin); return end - begin; }
char* begin; char* begin;
char* end; char* end;
}; };
struct const_interval struct const_interval
{ {
const_interval(char const* begin, char const* end) const_interval(char const* begin, char const* end)
: begin(begin) : begin(begin)
, end(end) , end(end)
{} {}
char operator[](int index) const char operator[](int index) const
{ {
assert(begin + index < end); assert(begin + index < end);
return begin[index]; return begin[index];
} }
bool operator==(const const_interval& p_interval) bool operator==(const const_interval& p_interval)
{ {
return (begin == p_interval.begin return (begin == p_interval.begin
&& end == p_interval.end); && end == p_interval.end);
} }
int left() const { assert(end >= begin); return end - begin; } int left() const { assert(end >= begin); return end - begin; }
char const* begin; char const* begin;
char const* end; char const* end;
}; };
typedef std::pair<const_interval, const_interval> interval_type; buffer(std::size_t n = 0)
: m_begin(0)
, m_end(0)
, m_last(0)
{
if (n) resize(n);
}
buffer(std::size_t n = 0); buffer(buffer const& b)
~buffer(); : m_begin(0)
, m_end(0)
, m_last(0)
{
if (b.size() == 0) return;
resize(b.size());
std::memcpy(m_begin, b.begin(), b.size());
}
interval allocate(std::size_t n); buffer& operator=(buffer const& b)
void insert(char const* first, char const* last); {
void erase(std::size_t n); resize(b.size());
std::size_t size() const; std::memcpy(m_begin, b.begin(), b.size());
std::size_t capacity() const; return *this;
void reserve(std::size_t n); }
interval_type data() const;
bool empty() const;
std::size_t space_left() const; ~buffer()
{
::operator delete (m_begin);
}
char const* raw_data() const buffer::interval data() { return interval(m_begin, m_end); }
{ buffer::const_interval data() const { return const_interval(m_begin, m_end); }
return m_first;
} void resize(std::size_t n)
{
reserve(n);
m_end = m_begin + n;
}
#ifndef NDEBUG void insert(char* point, char const* first, char const* last)
void check_invariant() const; {
#endif std::size_t p = point - m_begin;
if (point == m_end)
{
resize(size() + last - first);
std::memcpy(m_begin + p, first, last - first);
return;
}
resize(size() + last - first);
std::memmove(m_begin + p + (last - first), m_begin + p, last - first);
std::memcpy(m_begin + p, first, last - first);
}
void erase(char* begin, char* end)
{
assert(end <= m_end);
assert(begin >= m_begin);
assert(begin <= end);
if (end == m_end)
{
resize(begin - m_begin);
return;
}
std::memmove(begin, end, m_end - end);
m_end = begin + (m_end - end);
}
void clear() { m_end = m_begin; }
std::size_t size() const { return m_end - m_begin; }
std::size_t capacity() const { return m_last - m_begin; }
void reserve(std::size_t n)
{
if (n <= capacity()) return;
assert(n > 0);
char* buf = (char*)::operator new(n);
std::size_t s = size();
std::memcpy(buf, m_begin, s);
::operator delete (m_begin);
m_begin = buf;
m_end = buf + s;
m_last = m_begin + n;
}
bool empty() const { return m_begin == m_end; }
char& operator[](std::size_t i) { assert(i >= 0 && i < size()); return m_begin[i]; }
char const& operator[](std::size_t i) const { assert(i >= 0 && i < size()); return m_begin[i]; }
char* begin() { return m_begin; }
char const* begin() const { return m_begin; }
char* end() { return m_end; }
char const* end() const { return m_end; }
void swap(buffer& b)
{
using std::swap;
swap(m_begin, b.m_begin);
swap(m_end, b.m_end);
swap(m_last, b.m_last);
}
private: private:
char* m_first; char* m_begin; // first
char* m_last; char* m_end; // one passed end of size
char* m_write_cursor; char* m_last; // one passed end of allocation
char* m_read_cursor;
char* m_read_end;
bool m_empty;
#ifdef TORRENT_BUFFER_DEBUG
mutable std::vector<char> m_debug;
mutable int m_pending_copy;
#endif
}; };
inline buffer::buffer(std::size_t n)
: m_first((char*)::operator new(n))
, m_last(m_first + n)
, m_write_cursor(m_first)
, m_read_cursor(m_first)
, m_read_end(m_last)
, m_empty(true)
{
#ifdef TORRENT_BUFFER_DEBUG
m_pending_copy = 0;
#endif
}
inline buffer::~buffer()
{
::operator delete (m_first);
}
inline buffer::interval buffer::allocate(std::size_t n)
{
assert(m_read_cursor <= m_read_end || m_empty);
INVARIANT_CHECK;
#ifdef TORRENT_BUFFER_DEBUG
if (m_pending_copy)
{
std::copy(m_write_cursor - m_pending_copy, m_write_cursor
, m_debug.end() - m_pending_copy);
m_pending_copy = 0;
}
m_debug.resize(m_debug.size() + n);
m_pending_copy = n;
#endif
if (m_read_cursor < m_write_cursor || m_empty)
{
// ..R***W..
if (m_last - m_write_cursor >= (std::ptrdiff_t)n)
{
interval ret(m_write_cursor, m_write_cursor + n);
m_write_cursor += n;
m_read_end = m_write_cursor;
assert(m_read_cursor <= m_read_end);
if (n) m_empty = false;
return ret;
}
if (m_read_cursor - m_first >= (std::ptrdiff_t)n)
{
m_read_end = m_write_cursor;
interval ret(m_first, m_first + n);
m_write_cursor = m_first + n;
assert(m_read_cursor <= m_read_end);
if (n) m_empty = false;
return ret;
}
reserve(capacity() + n - (m_last - m_write_cursor));
assert(m_last - m_write_cursor >= (std::ptrdiff_t)n);
interval ret(m_write_cursor, m_write_cursor + n);
m_write_cursor += n;
m_read_end = m_write_cursor;
if (n) m_empty = false;
assert(m_read_cursor <= m_read_end);
return ret;
}
//**W...R**
if (m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n)
{
interval ret(m_write_cursor, m_write_cursor + n);
m_write_cursor += n;
if (n) m_empty = false;
return ret;
}
reserve(capacity() + n - (m_read_cursor - m_write_cursor));
assert(m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n);
interval ret(m_write_cursor, m_write_cursor + n);
m_write_cursor += n;
if (n) m_empty = false;
return ret;
}
inline void buffer::insert(char const* first, char const* last)
{
INVARIANT_CHECK;
std::size_t n = last - first;
#ifdef TORRENT_BUFFER_DEBUG
if (m_pending_copy)
{
std::copy(m_write_cursor - m_pending_copy, m_write_cursor
, m_debug.end() - m_pending_copy);
m_pending_copy = 0;
}
m_debug.insert(m_debug.end(), first, last);
#endif
if (space_left() < n)
{
reserve(capacity() + n);
}
m_empty = false;
char const* end = (m_last - m_write_cursor) < (std::ptrdiff_t)n ?
m_last : m_write_cursor + n;
std::size_t copied = end - m_write_cursor;
std::memcpy(m_write_cursor, first, copied);
m_write_cursor += copied;
if (m_write_cursor > m_read_end) m_read_end = m_write_cursor;
first += copied;
n -= copied;
if (n == 0) return;
assert(m_write_cursor == m_last);
m_write_cursor = m_first;
memcpy(m_write_cursor, first, n);
m_write_cursor += n;
}
inline void buffer::erase(std::size_t n)
{
INVARIANT_CHECK;
if (n == 0) return;
assert(!m_empty);
#ifndef NDEBUG
int prev_size = size();
#endif
assert(m_read_cursor <= m_read_end);
m_read_cursor += n;
if (m_read_cursor > m_read_end)
{
m_read_cursor = m_first + (m_read_cursor - m_read_end);
assert(m_read_cursor <= m_write_cursor);
}
m_empty = m_read_cursor == m_write_cursor;
assert(prev_size - n == size());
#ifdef TORRENT_BUFFER_DEBUG
m_debug.erase(m_debug.begin(), m_debug.begin() + n);
#endif
}
inline std::size_t buffer::size() const
{
// ...R***W.
if (m_read_cursor < m_write_cursor)
{
return m_write_cursor - m_read_cursor;
}
// ***W..R*
else
{
if (m_empty) return 0;
return (m_write_cursor - m_first) + (m_read_end - m_read_cursor);
}
}
inline std::size_t buffer::capacity() const
{
return m_last - m_first;
}
inline void buffer::reserve(std::size_t size)
{
std::size_t n = (std::size_t)(capacity() * 1.f);
if (n < size) n = size;
char* buf = (char*)::operator new(n);
char* old = m_first;
if (m_read_cursor < m_write_cursor)
{
// ...R***W.<>.
std::memcpy(
buf + (m_read_cursor - m_first)
, m_read_cursor
, m_write_cursor - m_read_cursor
);
m_write_cursor = buf + (m_write_cursor - m_first);
m_read_cursor = buf + (m_read_cursor - m_first);
m_read_end = m_write_cursor;
m_first = buf;
m_last = buf + n;
}
else
{
// **W..<>.R**
std::size_t skip = n - (m_last - m_first);
std::memcpy(buf, m_first, m_write_cursor - m_first);
std::memcpy(
buf + (m_read_cursor - m_first) + skip
, m_read_cursor
, m_last - m_read_cursor
);
m_write_cursor = buf + (m_write_cursor - m_first);
if (!m_empty)
{
m_read_cursor = buf + (m_read_cursor - m_first) + skip;
m_read_end = buf + (m_read_end - m_first) + skip;
}
else
{
m_read_cursor = m_write_cursor;
m_read_end = m_write_cursor;
}
m_first = buf;
m_last = buf + n;
}
::operator delete (old);
}
#ifndef NDEBUG
inline void buffer::check_invariant() const
{
assert(m_read_end >= m_read_cursor);
assert(m_last >= m_read_cursor);
assert(m_last >= m_write_cursor);
assert(m_last >= m_first);
assert(m_first <= m_read_cursor);
assert(m_first <= m_write_cursor);
#ifdef TORRENT_BUFFER_DEBUG
int a = m_debug.size();
int b = size();
(void)a;
(void)b;
assert(m_debug.size() == size());
#endif
}
#endif
inline buffer::interval_type buffer::data() const
{
INVARIANT_CHECK;
#ifdef TORRENT_BUFFER_DEBUG
if (m_pending_copy)
{
std::copy(m_write_cursor - m_pending_copy, m_write_cursor
, m_debug.end() - m_pending_copy);
m_pending_copy = 0;
}
#endif
// ...R***W.
if (m_read_cursor < m_write_cursor)
{
#ifdef TORRENT_BUFFER_DEBUG
assert(m_debug.size() == size());
assert(std::equal(m_debug.begin(), m_debug.end(), m_read_cursor));
#endif
return interval_type(
const_interval(m_read_cursor, m_write_cursor)
, const_interval(m_last, m_last)
);
}
// **W...R**
else
{
if (m_read_cursor == m_read_end)
{
#ifdef TORRENT_BUFFER_DEBUG
assert(m_debug.size() == size());
assert(std::equal(m_debug.begin(), m_debug.end(), m_first));
#endif
return interval_type(
const_interval(m_first, m_write_cursor)
, const_interval(m_last, m_last));
}
#ifdef TORRENT_BUFFER_DEBUG
assert(m_debug.size() == size());
assert(std::equal(m_debug.begin(), m_debug.begin() + (m_read_end
- m_read_cursor), m_read_cursor));
assert(std::equal(m_debug.begin() + (m_read_end - m_read_cursor), m_debug.end()
, m_first));
#endif
assert(m_read_cursor <= m_read_end || m_empty);
return interval_type(
const_interval(m_read_cursor, m_read_end)
, const_interval(m_first, m_write_cursor)
);
}
}
inline bool buffer::empty() const
{
return m_empty;
}
inline std::size_t buffer::space_left() const
{
if (m_empty) return m_last - m_first;
// ...R***W.
if (m_read_cursor < m_write_cursor)
{
return (m_last - m_write_cursor) + (m_read_cursor - m_first);
}
// ***W..R*
else
{
return m_read_cursor - m_write_cursor;
}
}
} }

View File

@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
std::vector<address> const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec); std::vector<address> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec);
} }
#endif #endif

View File

@ -510,7 +510,7 @@ namespace libtorrent
int m_packet_size; int m_packet_size;
int m_recv_pos; int m_recv_pos;
std::vector<char> m_recv_buffer; buffer m_recv_buffer;
// this is the buffer where data that is // this is the buffer where data that is
// to be sent is stored until it gets // to be sent is stored until it gets
@ -521,7 +521,7 @@ namespace libtorrent
// waiting for a async_write operation on one // waiting for a async_write operation on one
// buffer, the other is used to write data to // buffer, the other is used to write data to
// be queued up. // be queued up.
std::vector<char> m_send_buffer[2]; buffer m_send_buffer[2];
// the current send buffer is the one to write to. // the current send buffer is the one to write to.
// (m_current_send_buffer + 1) % 2 is the // (m_current_send_buffer + 1) % 2 is the
// buffer we're currently waiting for. // buffer we're currently waiting for.

View File

@ -98,6 +98,21 @@ namespace libtorrent
typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer; typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer;
inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep)
{
address const& addr = ep.address();
asio::error_code ec;
std::string a = addr.to_string(ec);
if (ec) return os;
if (addr.is_v6())
os << "[" << a << "]:";
else
os << a << ":";
os << ep.port();
return os;
}
namespace detail namespace detail
{ {
template<class OutIt> template<class OutIt>

View File

@ -113,6 +113,7 @@ namespace libtorrent
std::string url; std::string url;
int key; int key;
int num_want; int num_want;
std::string ipv6;
}; };
struct TORRENT_EXPORT request_callback struct TORRENT_EXPORT request_callback

View File

@ -232,18 +232,18 @@ namespace aux
// -------------- remote_endpoint ----------- // -------------- remote_endpoint -----------
template <class EndpointType, class Error_Handler = boost::mpl::void_> template <class EndpointType>
struct remote_endpoint_visitor struct remote_endpoint_visitor_ec
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
remote_endpoint_visitor(Error_Handler const& error_handler) remote_endpoint_visitor_ec(asio::error_code& ec)
: error_handler(error_handler) : error_code(ec)
{} {}
template <class T> template <class T>
EndpointType operator()(T* p) const EndpointType operator()(T* p) const
{ {
return p->remote_endpoint(error_handler); return p->remote_endpoint(error_code);
} }
EndpointType operator()(boost::blank) const EndpointType operator()(boost::blank) const
@ -251,11 +251,11 @@ namespace aux
return EndpointType(); return EndpointType();
} }
Error_Handler const& error_handler; asio::error_code& error_code;
}; };
template <class EndpointType> template <class EndpointType>
struct remote_endpoint_visitor<EndpointType, boost::mpl::void_> struct remote_endpoint_visitor
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
template <class T> template <class T>
@ -272,18 +272,18 @@ namespace aux
// -------------- local_endpoint ----------- // -------------- local_endpoint -----------
template <class EndpointType, class Error_Handler = boost::mpl::void_> template <class EndpointType>
struct local_endpoint_visitor struct local_endpoint_visitor_ec
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
local_endpoint_visitor(Error_Handler const& error_handler) local_endpoint_visitor_ec(asio::error_code& ec)
: error_handler(error_handler) : error_code(ec)
{} {}
template <class T> template <class T>
EndpointType operator()(T* p) const EndpointType operator()(T* p) const
{ {
return p->local_endpoint(error_handler); return p->local_endpoint(error_code);
} }
EndpointType operator()(boost::blank) const EndpointType operator()(boost::blank) const
@ -291,11 +291,11 @@ namespace aux
return EndpointType(); return EndpointType();
} }
Error_Handler const& error_handler; asio::error_code& error_code;
}; };
template <class EndpointType> template <class EndpointType>
struct local_endpoint_visitor<EndpointType, boost::mpl::void_> struct local_endpoint_visitor
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
template <class T> template <class T>
@ -665,12 +665,11 @@ public:
return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant); return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant);
} }
template <class Error_Handler> endpoint_type remote_endpoint(asio::error_code& ec)
endpoint_type remote_endpoint(Error_Handler const& error_handler)
{ {
assert(instantiated()); assert(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
aux::remote_endpoint_visitor<endpoint_type, Error_Handler>(error_handler), m_variant aux::remote_endpoint_visitor_ec<endpoint_type>(ec), m_variant
); );
} }
@ -680,12 +679,11 @@ public:
return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant); return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant);
} }
template <class Error_Handler> endpoint_type local_endpoint(asio::error_code& ec)
endpoint_type local_endpoint(Error_Handler const& error_handler)
{ {
assert(instantiated()); assert(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
aux::local_endpoint_visitor<endpoint_type, Error_Handler>(error_handler), m_variant aux::local_endpoint_visitor_ec<endpoint_type>(ec), m_variant
); );
} }

View File

@ -65,7 +65,7 @@ namespace libtorrent {
alert_manager::alert_manager() alert_manager::alert_manager()
: m_severity(alert::none) : m_severity(alert::fatal)
{} {}
alert_manager::~alert_manager() alert_manager::~alert_manager()

View File

@ -84,6 +84,14 @@ namespace libtorrent
return addr.to_v6().is_multicast(); return addr.to_v6().is_multicast();
} }
bool is_any(address const& addr)
{
if (addr.is_v4())
return addr.to_v4() == address_v4::any();
else
return addr.to_v6() == address_v6::any();
}
broadcast_socket::broadcast_socket(asio::io_service& ios broadcast_socket::broadcast_socket(asio::io_service& ios
, udp::endpoint const& multicast_endpoint , udp::endpoint const& multicast_endpoint
, receive_handler_t const& handler , receive_handler_t const& handler

View File

@ -50,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/version.hpp" #include "libtorrent/version.hpp"
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/enum_net.hpp"
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
#include "libtorrent/pe_crypto.hpp" #include "libtorrent/pe_crypto.hpp"
@ -1475,18 +1474,14 @@ namespace libtorrent
detail::write_address(remote().address(), out); detail::write_address(remote().address(), out);
handshake["yourip"] = remote_address; handshake["yourip"] = remote_address;
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
asio::error_code ec;
std::vector<address> const& interfaces = enum_net_interfaces(get_socket()->io_service(), ec); tcp::endpoint ep = m_ses.get_ipv6_interface();
for (std::vector<address>::const_iterator i = interfaces.begin() if (ep != tcp::endpoint())
, end(interfaces.end()); i != end; ++i)
{ {
// TODO: only use global IPv6 addresses
if (!i->is_v6() || i->to_v6().is_link_local()) continue;
std::string ipv6_address; std::string ipv6_address;
std::back_insert_iterator<std::string> out(ipv6_address); std::back_insert_iterator<std::string> out(ipv6_address);
detail::write_address(*i, out); detail::write_address(ep.address(), out);
handshake["ipv6"] = ipv6_address; handshake["ipv6"] = ipv6_address;
break;
} }
// loop backwards, to make the first extension be the last // loop backwards, to make the first extension be the last

View File

@ -40,10 +40,9 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
std::vector<address> const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) std::vector<address> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec)
{ {
static std::vector<address> ret; std::vector<address> ret;
if (!ret.empty()) return ret;
#if defined __linux__ || defined __MACH__ || defined(__FreeBSD__) #if defined __linux__ || defined __MACH__ || defined(__FreeBSD__)
int s = socket(AF_INET, SOCK_DGRAM, 0); int s = socket(AF_INET, SOCK_DGRAM, 0);

View File

@ -428,6 +428,13 @@ namespace libtorrent
m_send_buffer += "supportcrypto=1&"; m_send_buffer += "supportcrypto=1&";
#endif #endif
if (!url_has_argument(request, "ipv6") && !req.ipv6.empty())
{
m_send_buffer += "ipv6=";
m_send_buffer += req.ipv6;
m_send_buffer += '&';
}
// extension that tells the tracker that // extension that tells the tracker that
// we don't need any peer_id's in the response // we don't need any peer_id's in the response
if (!url_has_argument(request, "no_peer_id")) if (!url_has_argument(request, "no_peer_id"))

View File

@ -2082,7 +2082,8 @@ namespace libtorrent
p.remote_dl_rate = 0; p.remote_dl_rate = 0;
} }
p.send_buffer_size = send_buffer_size(); p.send_buffer_size = int(m_send_buffer[0].capacity()
+ m_send_buffer[1].capacity());
} }
void peer_connection::cut_receive_buffer(int size, int packet_size) void peer_connection::cut_receive_buffer(int size, int packet_size)
@ -2512,7 +2513,7 @@ namespace libtorrent
void peer_connection::send_buffer(char const* begin, char const* end) void peer_connection::send_buffer(char const* begin, char const* end)
{ {
std::vector<char>& buf = m_send_buffer[m_current_send_buffer]; buffer& buf = m_send_buffer[m_current_send_buffer];
buf.insert(buf.end(), begin, end); buf.insert(buf.end(), begin, end);
setup_send(); setup_send();
} }
@ -2521,7 +2522,7 @@ namespace libtorrent
// return value is destructed // return value is destructed
buffer::interval peer_connection::allocate_send_buffer(int size) buffer::interval peer_connection::allocate_send_buffer(int size)
{ {
std::vector<char>& buf = m_send_buffer[m_current_send_buffer]; buffer& buf = m_send_buffer[m_current_send_buffer];
buf.resize(buf.size() + size); buf.resize(buf.size() + size);
buffer::interval ret(&buf[0] + buf.size() - size, &buf[0] + buf.size()); buffer::interval ret(&buf[0] + buf.size() - size, &buf[0] + buf.size());
return ret; return ret;
@ -2588,7 +2589,7 @@ namespace libtorrent
&& m_recv_pos == 0 && m_recv_pos == 0
&& (m_recv_buffer.capacity() - m_packet_size) > 128) && (m_recv_buffer.capacity() - m_packet_size) > 128)
{ {
std::vector<char>(m_packet_size).swap(m_recv_buffer); buffer(m_packet_size).swap(m_recv_buffer);
} }
int max_receive = m_packet_size - m_recv_pos; int max_receive = m_packet_size - m_recv_pos;
@ -2807,7 +2808,7 @@ namespace libtorrent
if (int(m_send_buffer[i].size()) < 64 if (int(m_send_buffer[i].size()) < 64
&& int(m_send_buffer[i].capacity()) > 128) && int(m_send_buffer[i].capacity()) > 128)
{ {
std::vector<char> tmp(m_send_buffer[i]); buffer tmp(m_send_buffer[i]);
tmp.swap(m_send_buffer[i]); tmp.swap(m_send_buffer[i]);
assert(m_send_buffer[i].capacity() == m_send_buffer[i].size()); assert(m_send_buffer[i].capacity() == m_send_buffer[i].size());
} }

View File

@ -162,6 +162,18 @@ namespace
tcp::endpoint const& m_ep; tcp::endpoint const& m_ep;
}; };
struct match_peer_id
{
match_peer_id(peer_id const& id_)
: m_id(id_)
{}
bool operator()(policy::peer const& p) const
{ return p.connection && p.connection->pid() == m_id; }
peer_id const& m_id;
};
struct match_peer_connection struct match_peer_connection
{ {
match_peer_connection(peer_connection const& c) match_peer_connection(peer_connection const& c)
@ -1030,6 +1042,12 @@ namespace libtorrent
m_peers.begin() m_peers.begin()
, m_peers.end() , m_peers.end()
, match_peer_endpoint(remote)); , match_peer_endpoint(remote));
if (i == m_peers.end())
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_id(pid));
} }
else else
{ {
@ -1156,7 +1174,7 @@ namespace libtorrent
// data from now on // data from now on
void policy::unchoked(peer_connection& c) void policy::unchoked(peer_connection& c)
{ {
INVARIANT_CHECK; // INVARIANT_CHECK;
if (c.is_interesting()) if (c.is_interesting())
{ {
request_a_block(*m_torrent, c); request_a_block(*m_torrent, c);
@ -1166,7 +1184,7 @@ namespace libtorrent
// called when a peer is interested in us // called when a peer is interested in us
void policy::interested(peer_connection& c) void policy::interested(peer_connection& c)
{ {
INVARIANT_CHECK; // INVARIANT_CHECK;
assert(std::find_if(m_peers.begin(), m_peers.end() assert(std::find_if(m_peers.begin(), m_peers.end()
, boost::bind<bool>(std::equal_to<peer_connection*>(), bind(&peer::connection, _1) , boost::bind<bool>(std::equal_to<peer_connection*>(), bind(&peer::connection, _1)
@ -1278,7 +1296,7 @@ namespace libtorrent
*/ */
bool policy::connect_one_peer() bool policy::connect_one_peer()
{ {
INVARIANT_CHECK; // INVARIANT_CHECK;
assert(m_torrent->want_more_peers()); assert(m_torrent->want_more_peers());
@ -1291,7 +1309,6 @@ namespace libtorrent
try try
{ {
INVARIANT_CHECK;
p->connected = time_now(); p->connected = time_now();
p->connection = m_torrent->connect_to_peer(&*p); p->connection = m_torrent->connect_to_peer(&*p);
assert(p->connection == m_torrent->connection_for(p->ip)); assert(p->connection == m_torrent->connection_for(p->ip));
@ -1375,7 +1392,7 @@ namespace libtorrent
void policy::peer_is_interesting(peer_connection& c) void policy::peer_is_interesting(peer_connection& c)
{ {
INVARIANT_CHECK; // INVARIANT_CHECK;
c.send_interested(); c.send_interested();
if (c.has_peer_choked() if (c.has_peer_choked()

View File

@ -73,6 +73,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/kademlia/dht_tracker.hpp" #include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/enum_net.hpp"
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
@ -512,9 +513,8 @@ namespace detail
, m_download_channel(m_io_service, peer_connection::download_channel) , m_download_channel(m_io_service, peer_connection::download_channel)
, m_upload_channel(m_io_service, peer_connection::upload_channel) , m_upload_channel(m_io_service, peer_connection::upload_channel)
, m_tracker_manager(m_settings, m_tracker_proxy) , m_tracker_manager(m_settings, m_tracker_proxy)
, m_listen_port_range(listen_port_range) , m_listen_port_retries(listen_port_range.second - listen_port_range.first)
, m_listen_interface(address::from_string(listen_interface), listen_port_range.first) , m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
, m_external_listen_port(0)
, m_abort(false) , m_abort(false)
, m_max_uploads(8) , m_max_uploads(8)
, m_max_connections(200) , m_max_connections(200)
@ -661,129 +661,227 @@ namespace detail
*i = ' '; *i = ' ';
} }
void session_impl::open_listen_port() tcp::endpoint session_impl::get_ipv6_interface() const
{ {
try return m_ipv6_interface;
{ }
// create listener socket
m_listen_socket.reset(new socket_acceptor(m_io_service));
for(;;) session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep, int retries)
{ {
try asio::error_code ec;
{ listen_socket_t s;
m_listen_socket->open(m_listen_interface.protocol()); s.sock.reset(new socket_acceptor(m_io_service));
m_listen_socket->set_option(socket_acceptor::reuse_address(true)); s.sock->open(ep.protocol(), ec);
m_listen_socket->bind(m_listen_interface); s.sock->set_option(socket_acceptor::reuse_address(true), ec);
m_listen_socket->listen(); s.sock->bind(ep, ec);
m_listen_interface = m_listen_socket->local_endpoint(); while (ec && retries > 0)
m_external_listen_port = m_listen_interface.port(); {
break; ec = asio::error_code();
} assert(!ec);
catch (asio::system_error& e) --retries;
{ ep.port(ep.port() + 1);
// TODO: make sure this is correct s.sock->bind(ep, ec);
if (e.code() == asio::error::host_not_found
|| m_listen_interface.port() == 0)
{
if (m_alerts.should_post(alert::fatal))
{
std::string msg = "cannot listen on the given interface '"
+ m_listen_interface.address().to_string() + "'";
m_alerts.post_alert(listen_failed_alert(msg));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string msg = "cannot listen on the given interface '"
+ m_listen_interface.address().to_string() + "'";
(*m_logger) << msg << "\n";
#endif
assert(m_listen_socket.unique());
m_listen_socket.reset();
break;
}
m_listen_socket->close();
m_listen_interface.port(m_listen_interface.port() + 1);
if (m_listen_interface.port() > m_listen_port_range.second)
{
std::stringstream msg;
msg << "none of the ports in the range ["
<< m_listen_port_range.first
<< ", " << m_listen_port_range.second
<< "] could be opened for listening";
m_alerts.post_alert(listen_failed_alert(msg.str()));
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << msg.str() << "\n";
#endif
m_listen_socket.reset();
break;
}
}
}
} }
catch (asio::system_error& e) if (ec)
{
// instead of giving up, try
// let the OS pick a port
ep.port(0);
ec = asio::error_code();
s.sock->bind(ep, ec);
}
if (ec)
{
// not even that worked, give up
if (m_alerts.should_post(alert::fatal))
{
std::stringstream msg;
msg << "cannot bind to interface '";
print_endpoint(msg, ep) << "' " << ec.message();
m_alerts.post_alert(listen_failed_alert(ep, msg.str()));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::stringstream msg;
msg << "cannot bind to interface '";
print_endpoint(msg, ep) << "' " << ec.message();
(*m_logger) << msg.str() << "\n";
#endif
return listen_socket_t();
}
s.external_port = s.sock->local_endpoint(ec).port();
s.sock->listen(0, ec);
if (ec)
{ {
if (m_alerts.should_post(alert::fatal)) if (m_alerts.should_post(alert::fatal))
{ {
m_alerts.post_alert(listen_failed_alert( std::stringstream msg;
std::string("failed to open listen port: ") + e.what())); msg << "cannot listen on interface '";
print_endpoint(msg, ep) << "' " << ec.message();
m_alerts.post_alert(listen_failed_alert(ep, msg.str()));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::stringstream msg;
msg << "cannot listen on interface '";
print_endpoint(msg, ep) << "' " << ec.message();
(*m_logger) << msg.str() << "\n";
#endif
return listen_socket_t();
}
if (m_alerts.should_post(alert::fatal))
{
std::string msg = "listening on interface "
+ boost::lexical_cast<std::string>(ep);
m_alerts.post_alert(listen_succeeded_alert(ep, msg));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << "listening on: " << ep
<< " external port: " << s.external_port << "\n";
#endif
return s;
}
void session_impl::open_listen_port() throw()
{
// close the open listen sockets
m_listen_sockets.clear();
m_incoming_connection = false;
if (is_any(m_listen_interface.address()))
{
// this means we should open two listen sockets
// one for IPv4 and one for IPv6
listen_socket_t s = setup_listener(
tcp::endpoint(address_v4::any(), m_listen_interface.port())
, m_listen_port_retries);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock);
}
s = setup_listener(
tcp::endpoint(address_v6::any(), m_listen_interface.port())
, m_listen_port_retries);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock);
}
}
else
{
// we should only open a single listen socket, that
// binds to the given interface
listen_socket_t s = setup_listener(
m_listen_interface, m_listen_port_retries);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock);
} }
} }
if (m_listen_socket) m_ipv6_interface = tcp::endpoint();
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
, end(m_listen_sockets.end()); i != end; ++i)
{ {
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) asio::error_code ec;
(*m_logger) << "listening on port: " << m_listen_interface.port() tcp::endpoint ep = i->sock->local_endpoint(ec);
<< " external port: " << m_external_listen_port << "\n"; if (ec || ep.address().is_v4()) continue;
#endif
async_accept(); if (ep.address().to_v6() != address_v6::any())
if (m_natpmp.get()) {
m_natpmp->set_mappings(m_listen_interface.port(), 0); // if we're listening on a specific address
if (m_upnp.get()) // pick it
m_upnp->set_mappings(m_listen_interface.port(), 0); m_ipv6_interface = ep;
}
else
{
// if we're listening on any IPv6 address, enumerate them and
// pick the first non-local address
std::vector<address> const& ifs = enum_net_interfaces(m_io_service, ec);
for (std::vector<address>::const_iterator i = ifs.begin()
, end(ifs.end()); i != end; ++i)
{
if (i->is_v4() || i->to_v6().is_link_local() || i->to_v6().is_loopback()) continue;
m_ipv6_interface = tcp::endpoint(*i, ep.port());
break;
}
break;
}
}
if (!m_listen_sockets.empty())
{
asio::error_code ec;
tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
if (!ec)
{
if (m_natpmp.get()) m_natpmp->set_mappings(local.port(), 0);
if (m_upnp.get()) m_upnp->set_mappings(local.port(), 0);
}
} }
} }
void session_impl::async_accept() void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
{ {
shared_ptr<socket_type> c(new socket_type(m_io_service)); shared_ptr<socket_type> c(new socket_type(m_io_service));
c->instantiate<stream_socket>(); c->instantiate<stream_socket>();
m_listen_socket->async_accept(c->get<stream_socket>() listener->async_accept(c->get<stream_socket>()
, bind(&session_impl::on_incoming_connection, this, c , bind(&session_impl::on_incoming_connection, this, c
, weak_ptr<socket_acceptor>(m_listen_socket), _1)); , boost::weak_ptr<socket_acceptor>(listener), _1));
} }
void session_impl::on_incoming_connection(shared_ptr<socket_type> const& s void session_impl::on_incoming_connection(shared_ptr<socket_type> const& s
, weak_ptr<socket_acceptor> const& listen_socket, asio::error_code const& e) try , weak_ptr<socket_acceptor> listen_socket, asio::error_code const& e) try
{ {
if (listen_socket.expired()) boost::shared_ptr<socket_acceptor> listener = listen_socket.lock();
return; if (!listener) return;
if (e == asio::error::operation_aborted) if (e == asio::error::operation_aborted) return;
return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
assert(listen_socket.lock() == m_listen_socket);
if (m_abort) return; if (m_abort) return;
asio::error_code ec;
if (e) if (e)
{ {
tcp::endpoint ep = listener->local_endpoint(ec);
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string msg = "error accepting connection on '" std::string msg = "error accepting connection on '"
+ m_listen_interface.address().to_string() + "'"; + boost::lexical_cast<std::string>(ep) + "' " + e.message();
(*m_logger) << msg << "\n"; (*m_logger) << msg << "\n";
#endif #endif
assert(m_listen_socket.unique()); if (m_alerts.should_post(alert::fatal))
// try any random port {
m_listen_interface.port(0); std::string msg = "error accepting connection on '"
open_listen_port(); + boost::lexical_cast<std::string>(ep) + "' " + ec.message();
m_alerts.post_alert(listen_failed_alert(ep, msg));
}
return; return;
} }
async_accept(); async_accept(listener);
// we got a connection request! // we got a connection request!
m_incoming_connection = true; m_incoming_connection = true;
tcp::endpoint endp = s->remote_endpoint(); tcp::endpoint endp = s->remote_endpoint(ec);
if (ec)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << endp << " <== INCOMING CONNECTION FAILED, could "
"not retrieve remote endpoint " << ec.message() << "\n";
#endif
return;
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << endp << " <== INCOMING CONNECTION\n"; (*m_logger) << endp << " <== INCOMING CONNECTION\n";
@ -803,28 +901,22 @@ namespace detail
// check if we have any active torrents // check if we have any active torrents
// if we don't reject the connection // if we don't reject the connection
if (m_torrents.empty()) if (m_torrents.empty()) return;
bool has_active_torrent = false;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{ {
return; if (!i->second->is_paused())
}
else
{
bool has_active_torrent = false;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{ {
if (!i->second->is_paused()) has_active_torrent = true;
{ break;
has_active_torrent = true;
break;
}
} }
if (!has_active_torrent)
return;
} }
if (!has_active_torrent) return;
boost::intrusive_ptr<peer_connection> c( boost::intrusive_ptr<peer_connection> c(
new bt_peer_connection(*this, s, 0)); new bt_peer_connection(*this, s, 0));
#ifndef NDEBUG #ifndef NDEBUG
c->m_in_constructor = false; c->m_in_constructor = false;
#endif #endif
@ -1064,7 +1156,9 @@ namespace detail
if (t.should_request()) if (t.should_request())
{ {
tracker_request req = t.generate_tracker_request(); tracker_request req = t.generate_tracker_request();
req.listen_port = m_external_listen_port; req.listen_port = 0;
if (!m_listen_sockets.empty())
req.listen_port = m_listen_sockets.front().external_port;
req.key = m_key; req.key = m_key;
m_tracker_manager.queue_request(m_strand, m_half_open, req m_tracker_manager.queue_request(m_strand, m_half_open, req
, t.tracker_login(), m_listen_interface.address(), i->second); , t.tracker_login(), m_listen_interface.address(), i->second);
@ -1274,10 +1368,9 @@ namespace detail
{ {
eh_initializer(); eh_initializer();
if (m_listen_port_range.first != 0 && m_listen_port_range.second != 0)
{ {
session_impl::mutex_t::scoped_lock l(m_mutex); session_impl::mutex_t::scoped_lock l(m_mutex);
open_listen_port(); if (m_listen_interface.port() != 0) open_listen_port();
} }
ptime timer = time_now(); ptime timer = time_now();
@ -1331,8 +1424,10 @@ namespace detail
&& !i->second->trackers().empty()) && !i->second->trackers().empty())
{ {
tracker_request req = i->second->generate_tracker_request(); tracker_request req = i->second->generate_tracker_request();
assert(m_external_listen_port > 0); assert(!m_listen_sockets.empty());
req.listen_port = m_external_listen_port; req.listen_port = 0;
if (!m_listen_sockets.empty())
req.listen_port = m_listen_sockets.front().external_port;
req.key = m_key; req.key = m_key;
std::string login = i->second->tracker_login(); std::string login = i->second->tracker_login();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
@ -1347,8 +1442,8 @@ namespace detail
} }
} }
// close listen socket // close the listen sockets
m_listen_socket.reset(); m_listen_sockets.clear();
ptime start(time_now()); ptime start(time_now());
l.unlock(); l.unlock();
@ -1477,10 +1572,12 @@ namespace detail
, bool paused , bool paused
, void* userdata) , void* userdata)
{ {
assert(!save_path.empty());
// if you get this assert, you haven't managed to // if you get this assert, you haven't managed to
// open a listen port. call listen_on() first. // open a listen port. call listen_on() first.
assert(m_external_listen_port > 0); if (m_listen_sockets.empty())
assert(!save_path.empty()); throw std::runtime_error("no listen socket opened");
if (ti->begin_files() == ti->end_files()) if (ti->begin_files() == ti->end_files())
throw std::runtime_error("no files in torrent"); throw std::runtime_error("no files in torrent");
@ -1489,7 +1586,7 @@ namespace detail
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
mutex::scoped_lock l2(m_checker_impl.m_mutex); mutex::scoped_lock l2(m_checker_impl.m_mutex);
INVARIANT_CHECK; // INVARIANT_CHECK;
if (is_aborted()) if (is_aborted())
throw std::runtime_error("session is closing"); throw std::runtime_error("session is closing");
@ -1573,7 +1670,7 @@ namespace detail
// lock the session // lock the session
session_impl::mutex_t::scoped_lock l(m_mutex); session_impl::mutex_t::scoped_lock l(m_mutex);
INVARIANT_CHECK; // INVARIANT_CHECK;
// is the torrent already active? // is the torrent already active?
if (!find_torrent(info_hash).expired()) if (!find_torrent(info_hash).expired())
@ -1628,8 +1725,10 @@ namespace detail
{ {
tracker_request req = t.generate_tracker_request(); tracker_request req = t.generate_tracker_request();
assert(req.event == tracker_request::stopped); assert(req.event == tracker_request::stopped);
assert(m_external_listen_port > 0); assert(!m_listen_sockets.empty());
req.listen_port = m_external_listen_port; req.listen_port = 0;
if (!m_listen_sockets.empty())
req.listen_port = m_listen_sockets.front().external_port;
req.key = m_key; req.key = m_key;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
@ -1684,19 +1783,15 @@ namespace detail
if (net_interface && std::strlen(net_interface) > 0) if (net_interface && std::strlen(net_interface) > 0)
new_interface = tcp::endpoint(address::from_string(net_interface), port_range.first); new_interface = tcp::endpoint(address::from_string(net_interface), port_range.first);
else else
new_interface = tcp::endpoint(address(), port_range.first); new_interface = tcp::endpoint(address_v4::any(), port_range.first);
m_listen_port_range = port_range; m_listen_port_retries = port_range.second - port_range.first;
// if the interface is the same and the socket is open // if the interface is the same and the socket is open
// don't do anything // don't do anything
if (new_interface == m_listen_interface if (new_interface == m_listen_interface
&& m_listen_socket) return true; && !m_listen_sockets.empty()) return true;
if (m_listen_socket)
m_listen_socket.reset();
m_incoming_connection = false;
m_listen_interface = new_interface; m_listen_interface = new_interface;
open_listen_port(); open_listen_port();
@ -1723,13 +1818,14 @@ namespace detail
(*m_logger) << time_now_string() << "\n"; (*m_logger) << time_now_string() << "\n";
#endif #endif
return m_listen_socket; return !m_listen_sockets.empty();
} }
unsigned short session_impl::listen_port() const unsigned short session_impl::listen_port() const
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
return m_external_listen_port; if (m_listen_sockets.empty()) return 0;
return m_listen_sockets.front().external_port;;
} }
void session_impl::announce_lsd(sha1_hash const& ih) void session_impl::announce_lsd(sha1_hash const& ih)
@ -1777,7 +1873,8 @@ namespace detail
if (tcp_port != 0) if (tcp_port != 0)
{ {
m_external_listen_port = tcp_port; if (!m_listen_sockets.empty())
m_listen_sockets.front().external_port = tcp_port;
if (m_alerts.should_post(alert::info)) if (m_alerts.should_post(alert::info))
{ {
std::stringstream msg; std::stringstream msg;
@ -1801,7 +1898,7 @@ namespace detail
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
INVARIANT_CHECK; // INVARIANT_CHECK;
session_status s; session_status s;
s.has_incoming_connections = m_incoming_connection; s.has_incoming_connections = m_incoming_connection;
@ -1945,7 +2042,7 @@ namespace detail
bool session_impl::is_listening() const bool session_impl::is_listening() const
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
return m_listen_socket; return !m_listen_sockets.empty();
} }
session_impl::~session_impl() session_impl::~session_impl()

View File

@ -412,9 +412,9 @@ namespace libtorrent
m_last_dht_announce = now; m_last_dht_announce = now;
// TODO: There should be a way to abort an announce operation on the dht. // TODO: There should be a way to abort an announce operation on the dht.
// when the torrent is destructed // when the torrent is destructed
assert(m_ses.m_external_listen_port > 0); if (m_ses.m_listen_sockets.empty()) return;
m_ses.m_dht->announce(m_torrent_file->info_hash() m_ses.m_dht->announce(m_torrent_file->info_hash()
, m_ses.m_external_listen_port , m_ses.m_listen_sockets.front().external_port
, m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1))); , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
} }
#endif #endif
@ -1367,6 +1367,9 @@ namespace libtorrent
req.left = bytes_left(); req.left = bytes_left();
if (req.left == -1) req.left = 16*1024; if (req.left == -1) req.left = 16*1024;
req.event = m_event; req.event = m_event;
tcp::endpoint ep = m_ses.get_ipv6_interface();
if (ep != tcp::endpoint())
req.ipv6 = ep.address().to_string();
if (m_event != tracker_request::stopped) if (m_event != tracker_request::stopped)
m_event = tracker_request::none; m_event = tracker_request::none;

View File

@ -400,9 +400,7 @@ namespace libtorrent
{ {
if (i->first == "pieces" if (i->first == "pieces"
|| i->first == "piece length" || i->first == "piece length"
|| i->first == "length" || i->first == "length")
// || i->first == "files"
|| i->first == "name")
continue; continue;
m_extra_info[i->first] = i->second; m_extra_info[i->first] = i->second;
} }