diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 36c13c5ab..bfbfa8ae4 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -328,14 +328,33 @@ namespace libtorrent struct TORRENT_EXPORT listen_failed_alert: alert { listen_failed_alert( - const std::string& msg) + tcp::endpoint const& ep + , std::string const& msg) : alert(alert::fatal, msg) + , endpoint(ep) {} + tcp::endpoint endpoint; + virtual std::auto_ptr clone() const { return std::auto_ptr(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 clone() const + { return std::auto_ptr(new listen_succeeded_alert(*this)); } + }; + struct TORRENT_EXPORT portmap_error_alert: alert { portmap_error_alert(const std::string& msg) diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 9300a1ce3..afb358afe 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -189,11 +189,16 @@ namespace libtorrent #endif 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 const& listener); void on_incoming_connection(boost::shared_ptr const& s - , boost::weak_ptr const& as, asio::error_code const& e); + , boost::weak_ptr listener, asio::error_code const& e); // must be locked to access the data // in this struct @@ -393,8 +398,10 @@ namespace libtorrent // at startup int m_key; - // the range of ports we try to listen on - std::pair m_listen_port_range; + // the number of retries we make when binding the + // listen socket. For each retry the port number + // is incremented by one + int m_listen_port_retries; // the ip-address of the interface // we are supposed to listen on. @@ -402,17 +409,32 @@ namespace libtorrent // that we should let the os decide which // interface to listen on 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 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 sock; + }; + // since we might be listening on multiple interfaces + // we might need more than one listen socket + std::list m_listen_sockets; + + listen_socket_t setup_listener(tcp::endpoint ep, int retries); // the settings for the client session_settings m_settings; diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp index 23be67b0d..485d1bd1f 100644 --- a/libtorrent/include/libtorrent/broadcast_socket.hpp +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -44,6 +44,7 @@ namespace libtorrent bool is_local(address const& a); bool is_loopback(address const& addr); bool is_multicast(address const& addr); + bool is_any(address const& addr); address_v4 guess_local_address(asio::io_service&); diff --git a/libtorrent/include/libtorrent/buffer.hpp b/libtorrent/include/libtorrent/buffer.hpp index 0f37edcbd..6af8817e2 100644 --- a/libtorrent/include/libtorrent/buffer.hpp +++ b/libtorrent/include/libtorrent/buffer.hpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin +Copyright (c) 2007, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -32,9 +32,8 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef LIBTORRENT_BUFFER_HPP #define LIBTORRENT_BUFFER_HPP -//#define TORRENT_BUFFER_DEBUG - #include +#include #include "libtorrent/invariant_check.hpp" #include "libtorrent/assert.hpp" @@ -43,410 +42,157 @@ namespace libtorrent { class buffer { public: - struct interval - { - interval(char* begin, char* end) - : begin(begin) - , end(end) - {} + struct interval + { + interval(char* begin, char* end) + : begin(begin) + , end(end) + {} - char operator[](int index) const - { - assert(begin + index < end); - return begin[index]; - } + char operator[](int index) const + { + assert(begin + index < end); + return begin[index]; + } - int left() const { assert(end >= begin); return end - begin; } + int left() const { assert(end >= begin); return end - begin; } - char* begin; - char* end; - }; + char* begin; + char* end; + }; - struct const_interval - { - const_interval(char const* begin, char const* end) - : begin(begin) - , end(end) - {} + struct const_interval + { + const_interval(char const* begin, char const* end) + : begin(begin) + , end(end) + {} - char operator[](int index) const - { - assert(begin + index < end); - return begin[index]; - } + char operator[](int index) const + { + assert(begin + index < end); + return begin[index]; + } - bool operator==(const const_interval& p_interval) - { - return (begin == p_interval.begin - && end == p_interval.end); - } + bool operator==(const const_interval& p_interval) + { + return (begin == p_interval.begin + && 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* end; - }; + char const* begin; + char const* end; + }; - typedef std::pair 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(buffer const& b) + : 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); - void insert(char const* first, char const* last); - void erase(std::size_t n); - std::size_t size() const; - std::size_t capacity() const; - void reserve(std::size_t n); - interval_type data() const; - bool empty() const; + buffer& operator=(buffer const& b) + { + resize(b.size()); + std::memcpy(m_begin, b.begin(), b.size()); + return *this; + } - std::size_t space_left() const; + ~buffer() + { + ::operator delete (m_begin); + } - char const* raw_data() const - { - return m_first; - } + buffer::interval data() { return interval(m_begin, m_end); } + buffer::const_interval data() const { return const_interval(m_begin, m_end); } + + void resize(std::size_t n) + { + reserve(n); + m_end = m_begin + n; + } -#ifndef NDEBUG - void check_invariant() const; -#endif - + void insert(char* point, char const* first, char const* last) + { + 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: - char* m_first; - char* m_last; - char* m_write_cursor; - char* m_read_cursor; - char* m_read_end; - bool m_empty; -#ifdef TORRENT_BUFFER_DEBUG - mutable std::vector m_debug; - mutable int m_pending_copy; -#endif + char* m_begin; // first + char* m_end; // one passed end of size + char* m_last; // one passed end of allocation }; -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; - } -} } diff --git a/libtorrent/include/libtorrent/enum_net.hpp b/libtorrent/include/libtorrent/enum_net.hpp index 0c6063a2b..0da76ff36 100644 --- a/libtorrent/include/libtorrent/enum_net.hpp +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - std::vector
const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec); + std::vector
enum_net_interfaces(asio::io_service& ios, asio::error_code& ec); } #endif diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index ea16a8d0a..ac9aa0322 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -510,7 +510,7 @@ namespace libtorrent int m_packet_size; int m_recv_pos; - std::vector m_recv_buffer; + buffer m_recv_buffer; // this is the buffer where data that is // to be sent is stored until it gets @@ -521,7 +521,7 @@ namespace libtorrent // waiting for a async_write operation on one // buffer, the other is used to write data to // be queued up. - std::vector m_send_buffer[2]; + buffer m_send_buffer[2]; // the current send buffer is the one to write to. // (m_current_send_buffer + 1) % 2 is the // buffer we're currently waiting for. diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp index c478a92ef..514be256c 100755 --- a/libtorrent/include/libtorrent/socket.hpp +++ b/libtorrent/include/libtorrent/socket.hpp @@ -98,6 +98,21 @@ namespace libtorrent typedef asio::basic_deadline_timer 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 { template diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index 57f7bd851..b1b4d87ac 100755 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -113,6 +113,7 @@ namespace libtorrent std::string url; int key; int num_want; + std::string ipv6; }; struct TORRENT_EXPORT request_callback diff --git a/libtorrent/include/libtorrent/variant_stream.hpp b/libtorrent/include/libtorrent/variant_stream.hpp index 8f9888519..4b32c9349 100644 --- a/libtorrent/include/libtorrent/variant_stream.hpp +++ b/libtorrent/include/libtorrent/variant_stream.hpp @@ -232,18 +232,18 @@ namespace aux // -------------- remote_endpoint ----------- - template - struct remote_endpoint_visitor + template + struct remote_endpoint_visitor_ec : boost::static_visitor { - remote_endpoint_visitor(Error_Handler const& error_handler) - : error_handler(error_handler) + remote_endpoint_visitor_ec(asio::error_code& ec) + : error_code(ec) {} template EndpointType operator()(T* p) const { - return p->remote_endpoint(error_handler); + return p->remote_endpoint(error_code); } EndpointType operator()(boost::blank) const @@ -251,11 +251,11 @@ namespace aux return EndpointType(); } - Error_Handler const& error_handler; + asio::error_code& error_code; }; template - struct remote_endpoint_visitor + struct remote_endpoint_visitor : boost::static_visitor { template @@ -272,18 +272,18 @@ namespace aux // -------------- local_endpoint ----------- - template - struct local_endpoint_visitor + template + struct local_endpoint_visitor_ec : boost::static_visitor { - local_endpoint_visitor(Error_Handler const& error_handler) - : error_handler(error_handler) + local_endpoint_visitor_ec(asio::error_code& ec) + : error_code(ec) {} template EndpointType operator()(T* p) const { - return p->local_endpoint(error_handler); + return p->local_endpoint(error_code); } EndpointType operator()(boost::blank) const @@ -291,11 +291,11 @@ namespace aux return EndpointType(); } - Error_Handler const& error_handler; + asio::error_code& error_code; }; template - struct local_endpoint_visitor + struct local_endpoint_visitor : boost::static_visitor { template @@ -665,12 +665,11 @@ public: return boost::apply_visitor(aux::remote_endpoint_visitor(), m_variant); } - template - endpoint_type remote_endpoint(Error_Handler const& error_handler) + endpoint_type remote_endpoint(asio::error_code& ec) { assert(instantiated()); return boost::apply_visitor( - aux::remote_endpoint_visitor(error_handler), m_variant + aux::remote_endpoint_visitor_ec(ec), m_variant ); } @@ -680,12 +679,11 @@ public: return boost::apply_visitor(aux::local_endpoint_visitor(), m_variant); } - template - endpoint_type local_endpoint(Error_Handler const& error_handler) + endpoint_type local_endpoint(asio::error_code& ec) { assert(instantiated()); return boost::apply_visitor( - aux::local_endpoint_visitor(error_handler), m_variant + aux::local_endpoint_visitor_ec(ec), m_variant ); } diff --git a/libtorrent/src/alert.cpp b/libtorrent/src/alert.cpp index b990db7e1..80ae6ead8 100755 --- a/libtorrent/src/alert.cpp +++ b/libtorrent/src/alert.cpp @@ -65,7 +65,7 @@ namespace libtorrent { alert_manager::alert_manager() - : m_severity(alert::none) + : m_severity(alert::fatal) {} alert_manager::~alert_manager() diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 3aaadcc81..359c0e0d2 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -84,6 +84,14 @@ namespace libtorrent 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 , udp::endpoint const& multicast_endpoint , receive_handler_t const& handler diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index ab61d98f9..e27a7f4c3 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -50,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" -#include "libtorrent/enum_net.hpp" #ifndef TORRENT_DISABLE_ENCRYPTION #include "libtorrent/pe_crypto.hpp" @@ -1475,18 +1474,14 @@ namespace libtorrent detail::write_address(remote().address(), out); handshake["yourip"] = remote_address; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; - asio::error_code ec; - std::vector
const& interfaces = enum_net_interfaces(get_socket()->io_service(), ec); - for (std::vector
::const_iterator i = interfaces.begin() - , end(interfaces.end()); i != end; ++i) + + tcp::endpoint ep = m_ses.get_ipv6_interface(); + if (ep != tcp::endpoint()) { - // TODO: only use global IPv6 addresses - if (!i->is_v6() || i->to_v6().is_link_local()) continue; std::string ipv6_address; std::back_insert_iterator out(ipv6_address); - detail::write_address(*i, out); + detail::write_address(ep.address(), out); handshake["ipv6"] = ipv6_address; - break; } // loop backwards, to make the first extension be the last diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp index 172719793..94c74e855 100644 --- a/libtorrent/src/enum_net.cpp +++ b/libtorrent/src/enum_net.cpp @@ -40,10 +40,9 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - std::vector
const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) + std::vector
enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) { - static std::vector
ret; - if (!ret.empty()) return ret; + std::vector
ret; #if defined __linux__ || defined __MACH__ || defined(__FreeBSD__) int s = socket(AF_INET, SOCK_DGRAM, 0); diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 0a0e59c48..64dea2e2e 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -428,6 +428,13 @@ namespace libtorrent m_send_buffer += "supportcrypto=1&"; #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 // we don't need any peer_id's in the response if (!url_has_argument(request, "no_peer_id")) diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 25bc0ba63..ad5087325 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -2082,7 +2082,8 @@ namespace libtorrent 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) @@ -2512,7 +2513,7 @@ namespace libtorrent void peer_connection::send_buffer(char const* begin, char const* end) { - std::vector& buf = m_send_buffer[m_current_send_buffer]; + buffer& buf = m_send_buffer[m_current_send_buffer]; buf.insert(buf.end(), begin, end); setup_send(); } @@ -2521,7 +2522,7 @@ namespace libtorrent // return value is destructed buffer::interval peer_connection::allocate_send_buffer(int size) { - std::vector& buf = m_send_buffer[m_current_send_buffer]; + buffer& buf = m_send_buffer[m_current_send_buffer]; buf.resize(buf.size() + size); buffer::interval ret(&buf[0] + buf.size() - size, &buf[0] + buf.size()); return ret; @@ -2588,7 +2589,7 @@ namespace libtorrent && m_recv_pos == 0 && (m_recv_buffer.capacity() - m_packet_size) > 128) { - std::vector(m_packet_size).swap(m_recv_buffer); + buffer(m_packet_size).swap(m_recv_buffer); } int max_receive = m_packet_size - m_recv_pos; @@ -2807,7 +2808,7 @@ namespace libtorrent if (int(m_send_buffer[i].size()) < 64 && int(m_send_buffer[i].capacity()) > 128) { - std::vector tmp(m_send_buffer[i]); + buffer tmp(m_send_buffer[i]); tmp.swap(m_send_buffer[i]); assert(m_send_buffer[i].capacity() == m_send_buffer[i].size()); } diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 4faed837e..49671c5db 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -162,6 +162,18 @@ namespace 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 { match_peer_connection(peer_connection const& c) @@ -1030,6 +1042,12 @@ namespace libtorrent m_peers.begin() , m_peers.end() , match_peer_endpoint(remote)); + + if (i == m_peers.end()) + i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_id(pid)); } else { @@ -1156,7 +1174,7 @@ namespace libtorrent // data from now on void policy::unchoked(peer_connection& c) { - INVARIANT_CHECK; +// INVARIANT_CHECK; if (c.is_interesting()) { request_a_block(*m_torrent, c); @@ -1166,7 +1184,7 @@ namespace libtorrent // called when a peer is interested in us void policy::interested(peer_connection& c) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(std::find_if(m_peers.begin(), m_peers.end() , boost::bind(std::equal_to(), bind(&peer::connection, _1) @@ -1278,7 +1296,7 @@ namespace libtorrent */ bool policy::connect_one_peer() { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(m_torrent->want_more_peers()); @@ -1291,7 +1309,6 @@ namespace libtorrent try { - INVARIANT_CHECK; p->connected = time_now(); p->connection = m_torrent->connect_to_peer(&*p); assert(p->connection == m_torrent->connection_for(p->ip)); @@ -1375,7 +1392,7 @@ namespace libtorrent void policy::peer_is_interesting(peer_connection& c) { - INVARIANT_CHECK; +// INVARIANT_CHECK; c.send_interested(); if (c.has_peer_choked() diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 6e1129b99..a58906156 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -73,6 +73,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/kademlia/dht_tracker.hpp" +#include "libtorrent/enum_net.hpp" #ifndef TORRENT_DISABLE_ENCRYPTION @@ -512,9 +513,8 @@ namespace detail , m_download_channel(m_io_service, peer_connection::download_channel) , m_upload_channel(m_io_service, peer_connection::upload_channel) , 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_external_listen_port(0) , m_abort(false) , m_max_uploads(8) , m_max_connections(200) @@ -661,129 +661,227 @@ namespace detail *i = ' '; } - void session_impl::open_listen_port() + tcp::endpoint session_impl::get_ipv6_interface() const { - try - { - // create listener socket - m_listen_socket.reset(new socket_acceptor(m_io_service)); + return m_ipv6_interface; + } - for(;;) - { - try - { - m_listen_socket->open(m_listen_interface.protocol()); - m_listen_socket->set_option(socket_acceptor::reuse_address(true)); - m_listen_socket->bind(m_listen_interface); - m_listen_socket->listen(); - m_listen_interface = m_listen_socket->local_endpoint(); - m_external_listen_port = m_listen_interface.port(); - break; - } - catch (asio::system_error& e) - { - // TODO: make sure this is correct - 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; - } - } - } + session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep, int retries) + { + asio::error_code ec; + listen_socket_t s; + s.sock.reset(new socket_acceptor(m_io_service)); + s.sock->open(ep.protocol(), ec); + s.sock->set_option(socket_acceptor::reuse_address(true), ec); + s.sock->bind(ep, ec); + while (ec && retries > 0) + { + ec = asio::error_code(); + assert(!ec); + --retries; + ep.port(ep.port() + 1); + s.sock->bind(ep, ec); } - 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)) { - m_alerts.post_alert(listen_failed_alert( - std::string("failed to open listen port: ") + e.what())); + std::stringstream msg; + 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(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::const_iterator i = m_listen_sockets.begin() + , end(m_listen_sockets.end()); i != end; ++i) { -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << "listening on port: " << m_listen_interface.port() - << " external port: " << m_external_listen_port << "\n"; -#endif - async_accept(); - if (m_natpmp.get()) - m_natpmp->set_mappings(m_listen_interface.port(), 0); - if (m_upnp.get()) - m_upnp->set_mappings(m_listen_interface.port(), 0); + asio::error_code ec; + tcp::endpoint ep = i->sock->local_endpoint(ec); + if (ec || ep.address().is_v4()) continue; + + if (ep.address().to_v6() != address_v6::any()) + { + // if we're listening on a specific address + // pick it + m_ipv6_interface = ep; + } + else + { + // if we're listening on any IPv6 address, enumerate them and + // pick the first non-local address + std::vector
const& ifs = enum_net_interfaces(m_io_service, ec); + for (std::vector
::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 const& listener) { shared_ptr c(new socket_type(m_io_service)); c->instantiate(); - m_listen_socket->async_accept(c->get() + listener->async_accept(c->get() , bind(&session_impl::on_incoming_connection, this, c - , weak_ptr(m_listen_socket), _1)); + , boost::weak_ptr(listener), _1)); } void session_impl::on_incoming_connection(shared_ptr const& s - , weak_ptr const& listen_socket, asio::error_code const& e) try + , weak_ptr listen_socket, asio::error_code const& e) try { - if (listen_socket.expired()) - return; + boost::shared_ptr listener = listen_socket.lock(); + if (!listener) return; - if (e == asio::error::operation_aborted) - return; + if (e == asio::error::operation_aborted) return; mutex_t::scoped_lock l(m_mutex); - assert(listen_socket.lock() == m_listen_socket); - if (m_abort) return; + asio::error_code ec; if (e) { + tcp::endpoint ep = listener->local_endpoint(ec); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) std::string msg = "error accepting connection on '" - + m_listen_interface.address().to_string() + "'"; + + boost::lexical_cast(ep) + "' " + e.message(); (*m_logger) << msg << "\n"; #endif - assert(m_listen_socket.unique()); - // try any random port - m_listen_interface.port(0); - open_listen_port(); + if (m_alerts.should_post(alert::fatal)) + { + std::string msg = "error accepting connection on '" + + boost::lexical_cast(ep) + "' " + ec.message(); + m_alerts.post_alert(listen_failed_alert(ep, msg)); + } return; } - async_accept(); + async_accept(listener); // we got a connection request! 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) (*m_logger) << endp << " <== INCOMING CONNECTION\n"; @@ -803,28 +901,22 @@ namespace detail // check if we have any active torrents // 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; - } - 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()) { - 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 c( - new bt_peer_connection(*this, s, 0)); + new bt_peer_connection(*this, s, 0)); #ifndef NDEBUG c->m_in_constructor = false; #endif @@ -1064,7 +1156,9 @@ namespace detail if (t.should_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; m_tracker_manager.queue_request(m_strand, m_half_open, req , t.tracker_login(), m_listen_interface.address(), i->second); @@ -1274,10 +1368,9 @@ namespace detail { eh_initializer(); - if (m_listen_port_range.first != 0 && m_listen_port_range.second != 0) { 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(); @@ -1331,8 +1424,10 @@ namespace detail && !i->second->trackers().empty()) { tracker_request req = i->second->generate_tracker_request(); - assert(m_external_listen_port > 0); - req.listen_port = m_external_listen_port; + assert(!m_listen_sockets.empty()); + req.listen_port = 0; + if (!m_listen_sockets.empty()) + req.listen_port = m_listen_sockets.front().external_port; req.key = m_key; std::string login = i->second->tracker_login(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -1347,8 +1442,8 @@ namespace detail } } - // close listen socket - m_listen_socket.reset(); + // close the listen sockets + m_listen_sockets.clear(); ptime start(time_now()); l.unlock(); @@ -1477,10 +1572,12 @@ namespace detail , bool paused , void* userdata) { + assert(!save_path.empty()); + // if you get this assert, you haven't managed to // open a listen port. call listen_on() first. - assert(m_external_listen_port > 0); - assert(!save_path.empty()); + if (m_listen_sockets.empty()) + throw std::runtime_error("no listen socket opened"); if (ti->begin_files() == ti->end_files()) throw std::runtime_error("no files in torrent"); @@ -1489,7 +1586,7 @@ namespace detail mutex_t::scoped_lock l(m_mutex); mutex::scoped_lock l2(m_checker_impl.m_mutex); - INVARIANT_CHECK; +// INVARIANT_CHECK; if (is_aborted()) throw std::runtime_error("session is closing"); @@ -1573,7 +1670,7 @@ namespace detail // lock the session session_impl::mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; +// INVARIANT_CHECK; // is the torrent already active? if (!find_torrent(info_hash).expired()) @@ -1628,8 +1725,10 @@ namespace detail { tracker_request req = t.generate_tracker_request(); assert(req.event == tracker_request::stopped); - assert(m_external_listen_port > 0); - req.listen_port = m_external_listen_port; + assert(!m_listen_sockets.empty()); + req.listen_port = 0; + if (!m_listen_sockets.empty()) + req.listen_port = m_listen_sockets.front().external_port; req.key = m_key; #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -1684,19 +1783,15 @@ namespace detail if (net_interface && std::strlen(net_interface) > 0) new_interface = tcp::endpoint(address::from_string(net_interface), port_range.first); 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 // don't do anything 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; open_listen_port(); @@ -1723,13 +1818,14 @@ namespace detail (*m_logger) << time_now_string() << "\n"; #endif - return m_listen_socket; + return !m_listen_sockets.empty(); } unsigned short session_impl::listen_port() const { 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) @@ -1777,7 +1873,8 @@ namespace detail 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)) { std::stringstream msg; @@ -1801,7 +1898,7 @@ namespace detail { mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; +// INVARIANT_CHECK; session_status s; s.has_incoming_connections = m_incoming_connection; @@ -1945,7 +2042,7 @@ namespace detail bool session_impl::is_listening() const { mutex_t::scoped_lock l(m_mutex); - return m_listen_socket; + return !m_listen_sockets.empty(); } session_impl::~session_impl() diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 252461bc6..6e941e9ec 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -412,9 +412,9 @@ namespace libtorrent m_last_dht_announce = now; // TODO: There should be a way to abort an announce operation on the dht. // 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_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))); } #endif @@ -1367,6 +1367,9 @@ namespace libtorrent req.left = bytes_left(); if (req.left == -1) req.left = 16*1024; 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) m_event = tracker_request::none; diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index d6dc27fa2..76c10e572 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -400,9 +400,7 @@ namespace libtorrent { if (i->first == "pieces" || i->first == "piece length" - || i->first == "length" -// || i->first == "files" - || i->first == "name") + || i->first == "length") continue; m_extra_info[i->first] = i->second; }