diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp index b36d4da22..dc9769840 100755 --- a/libtorrent/include/libtorrent/config.hpp +++ b/libtorrent/include/libtorrent/config.hpp @@ -67,5 +67,21 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_DEPRECATED #endif +// set up defines for target environments +#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \ + || defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \ + || defined __FreeBSD_kernel__ +#define TORRENT_BSD +#elif defined __linux__ +#define TORRENT_LINUX +#elif defined WIN32 +#define TORRENT_WINDOWS +#else +#warning unkown OS, assuming BSD +#define TORRENT_BSD +#endif + + + #endif // TORRENT_CONFIG_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/enum_net.hpp b/libtorrent/include/libtorrent/enum_net.hpp index a794c705c..4570e30eb 100644 --- a/libtorrent/include/libtorrent/enum_net.hpp +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -37,7 +37,26 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - std::vector
enum_net_interfaces(asio::io_service& ios, asio::error_code& ec); + + struct ip_interface + { + address interface_address; + address netmask; + }; + + // returns a list of the configured IP interfaces + // on the machine + std::vector enum_net_interfaces(asio::io_service& ios + , asio::error_code& ec); + + // returns true if the specified address is on the same + // local network as the specified interface + bool in_subnet(address const& addr, ip_interface const& iface); + + // returns true if the specified address is on the same + // local network as us + bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec); + address router_for_interface(address const interface, asio::error_code& ec); } diff --git a/libtorrent/include/libtorrent/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp index be8ec15cb..1d0f8d425 100644 --- a/libtorrent/include/libtorrent/upnp.hpp +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -230,11 +230,10 @@ private: bool m_disabled; bool m_closing; + bool m_ignore_outside_network; connection_queue& m_cc; - std::vector
m_filter; - #ifdef TORRENT_UPNP_LOGGING std::ofstream m_log; #endif diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 3437648d9..16f0a0728 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -79,12 +79,12 @@ namespace libtorrent { // make a best guess of the interface we're using and its IP asio::error_code ec; - std::vector
const& interfaces = enum_net_interfaces(ios, ec); + std::vector const& interfaces = enum_net_interfaces(ios, ec); address ret = address_v4::any(); - for (std::vector
::const_iterator i = interfaces.begin() + for (std::vector::const_iterator i = interfaces.begin() , end(interfaces.end()); i != end; ++i) { - address const& a = *i; + address const& a = i->interface_address; if (is_loopback(a) || is_multicast(a) || is_any(a)) continue; @@ -111,20 +111,20 @@ namespace libtorrent using namespace asio::ip::multicast; asio::error_code ec; - std::vector
interfaces = enum_net_interfaces(ios, ec); + std::vector interfaces = enum_net_interfaces(ios, ec); - for (std::vector
::const_iterator i = interfaces.begin() + for (std::vector::const_iterator i = interfaces.begin() , end(interfaces.end()); i != end; ++i) { // only broadcast to IPv4 addresses that are not local - if (!is_local(*i)) continue; + if (!is_local(i->interface_address)) continue; // only multicast on compatible networks - if (i->is_v4() != multicast_endpoint.address().is_v4()) continue; + if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue; // ignore any loopback interface - if (is_loopback(*i)) continue; + if (is_loopback(i->interface_address)) continue; boost::shared_ptr s(new datagram_socket(ios)); - if (i->is_v4()) + if (i->interface_address.is_v4()) { s->open(udp::v4(), ec); if (ec) continue; @@ -134,7 +134,7 @@ namespace libtorrent if (ec) continue; s->set_option(join_group(multicast_endpoint.address()), ec); if (ec) continue; - s->set_option(outbound_interface(i->to_v4()), ec); + s->set_option(outbound_interface(i->interface_address.to_v4()), ec); if (ec) continue; } else @@ -147,7 +147,7 @@ namespace libtorrent if (ec) continue; s->set_option(join_group(multicast_endpoint.address()), ec); if (ec) continue; -// s->set_option(outbound_interface(i->to_v6()), ec); +// s->set_option(outbound_interface(i->interface_address.to_v6()), ec); // if (ec) continue; } s->set_option(hops(255), ec); diff --git a/libtorrent/src/entry.cpp b/libtorrent/src/entry.cpp index 8219ecc06..c3e91044a 100755 --- a/libtorrent/src/entry.cpp +++ b/libtorrent/src/entry.cpp @@ -143,24 +143,28 @@ namespace libtorrent #endif entry::entry(dictionary_type const& v) + : m_type(undefined_t) { new(data) dictionary_type(v); m_type = dictionary_t; } entry::entry(string_type const& v) + : m_type(undefined_t) { new(data) string_type(v); m_type = string_t; } entry::entry(list_type const& v) + : m_type(undefined_t) { new(data) list_type(v); m_type = list_t; } entry::entry(integer_type const& v) + : m_type(undefined_t) { new(data) integer_type(v); m_type = int_t; @@ -216,8 +220,7 @@ namespace libtorrent void entry::construct(data_type t) { - m_type = t; - switch(m_type) + switch(t) { case int_t: new(data) integer_type; @@ -234,13 +237,14 @@ namespace libtorrent default: TORRENT_ASSERT(m_type == undefined_t); m_type = undefined_t; + return; } + m_type = t; } void entry::copy(entry const& e) { - m_type = e.m_type; - switch(m_type) + switch(e.m_type) { case int_t: new(data) integer_type(e.integer()); @@ -256,7 +260,9 @@ namespace libtorrent break; default: m_type = undefined_t; + return; } + m_type = e.m_type; } void entry::destruct() @@ -279,6 +285,7 @@ namespace libtorrent TORRENT_ASSERT(m_type == undefined_t); break; } + m_type = undefined_t; } void entry::swap(entry& e) diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp index 585fa0f38..3eb8df837 100644 --- a/libtorrent/src/enum_net.cpp +++ b/libtorrent/src/enum_net.cpp @@ -30,11 +30,13 @@ POSSIBILITY OF SUCH DAMAGE. */ -#if defined __linux__ || defined __MACH__ +#include "libtorrent/config.hpp" + +#if defined TORRENT_BSD || defined TORRENT_LINUX #include #include #include -#elif defined WIN32 +#elif defined TORRENT_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -46,11 +48,58 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - std::vector
enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) + namespace { - std::vector
ret; + address sockaddr_to_address(sockaddr const* sin) + { + if (sin->sa_family == AF_INET) + { + typedef asio::ip::address_v4::bytes_type bytes_t; + bytes_t b; + memcpy(&b[0], &((sockaddr_in const*)sin)->sin_addr, b.size()); + return address_v4(b); + } + else if (sin->sa_family == AF_INET6) + { + typedef asio::ip::address_v6::bytes_type bytes_t; + bytes_t b; + memcpy(&b[0], &((sockaddr_in6 const*)sin)->sin6_addr, b.size()); + return address_v6(b); + } + return address(); + } + } + + bool in_subnet(address const& addr, ip_interface const& iface) + { + if (addr.is_v4() != iface.interface_address.is_v4()) return false; + // since netmasks seems unreliable for IPv6 interfaces + // (MacOS X returns AF_INET addresses as bitmasks) assume + // that any IPv6 address belongs to the subnet of any + // interface with an IPv6 address + if (addr.is_v6()) return true; -#if defined __linux__ || defined __MACH__ || defined(__FreeBSD__) + return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong()) + == (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong()); + } + + bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec) + { + std::vector const& net = enum_net_interfaces(ios, ec); + if (ec) return false; + for (std::vector::const_iterator i = net.begin() + , end(net.end()); i != end; ++i) + { + if (in_subnet(addr, *i)) return true; + } + return false; + } + + std::vector enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) + { + std::vector ret; + +#if defined TORRENT_LINUX || defined TORRENT_BSD int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { @@ -63,11 +112,10 @@ namespace libtorrent ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + ec = asio::error_code(errno, asio::error::system_category); close(s); - ec = asio::error::fault; return ret; } - close(s); char *ifr = (char*)ifc.ifc_req; int remaining = ifc.ifc_len; @@ -75,36 +123,51 @@ namespace libtorrent while (remaining) { ifreq const& item = *reinterpret_cast(ifr); - if (item.ifr_addr.sa_family == AF_INET) + + if (item.ifr_addr.sa_family == AF_INET + || item.ifr_addr.sa_family == AF_INET6) { - typedef asio::ip::address_v4::bytes_type bytes_t; - bytes_t b; - memcpy(&b[0], &((sockaddr_in const*)&item.ifr_addr)->sin_addr, b.size()); - ret.push_back(address_v4(b)); - } - else if (item.ifr_addr.sa_family == AF_INET6) - { - typedef asio::ip::address_v6::bytes_type bytes_t; - bytes_t b; - memcpy(&b[0], &((sockaddr_in6 const*)&item.ifr_addr)->sin6_addr, b.size()); - ret.push_back(address_v6(b)); + ip_interface iface; + iface.interface_address = sockaddr_to_address(&item.ifr_addr); + + ifreq netmask = item; + if (ioctl(s, SIOCGIFNETMASK, &netmask) < 0) + { + if (iface.interface_address.is_v6()) + { + // this is expected to fail (at least on MacOS X) + iface.netmask = address_v6::any(); + } + else + { + ec = asio::error_code(errno, asio::error::system_category); + close(s); + return ret; + } + } + else + { + iface.netmask = sockaddr_to_address(&netmask.ifr_addr); + } + ret.push_back(iface); } -#if defined __MACH__ || defined(__FreeBSD__) +#if defined TORRENT_BSD int current_size = item.ifr_addr.sa_len + IFNAMSIZ; -#elif defined __linux__ +#elif defined TORRENT_LINUX int current_size = sizeof(ifreq); #endif ifr += current_size; remaining -= current_size; } + close(s); -#elif defined WIN32 +#elif defined TORRENT_WINDOWS SOCKET s = socket(AF_INET, SOCK_DGRAM, 0); if (s == SOCKET_ERROR) { - ec = asio::error::fault; + ec = asio::error_code(WSAGetLastError(), asio::error::system_category); return ret; } @@ -114,29 +177,36 @@ namespace libtorrent if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer, sizeof(buffer), &size, 0, 0) != 0) { + ec = asio::error_code(WSAGetLastError(), asio::error::system_category); closesocket(s); - ec = asio::error::fault; return ret; } closesocket(s); int n = size / sizeof(INTERFACE_INFO); + ip_interface iface; for (int i = 0; i < n; ++i) { - sockaddr_in *sockaddr = (sockaddr_in*)&buffer[i].iiAddress; - address a(address::from_string(inet_ntoa(sockaddr->sin_addr))); - if (a == address_v4::any()) continue; - ret.push_back(a); + iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address); + iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address); + if (iface.interface_address == address_v4::any()) continue; + ret.push_back(iface); } #else +#warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK // make a best guess of the interface we're using and its IP udp::resolver r(ios); - udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); + udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0")); + if (ec) return ret; + ip_interface iface; for (;i != udp::resolver_iterator(); ++i) { - ret.push_back(i->endpoint().address()); + iface.interface_address = i->endpoint().address(); + if (iface.interface_address.is_v4()) + iface.netmask = address_v4::netmask(iface.interface_address.to_v4()); + ret.push_back(iface); } #endif return ret; @@ -144,7 +214,7 @@ namespace libtorrent address router_for_interface(address const interface, asio::error_code& ec) { -#ifdef WIN32 +#ifdef TORRENT_WINDOWS // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); @@ -184,15 +254,22 @@ namespace libtorrent address ret; if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR) { - PIP_ADAPTER_INFO adapter = adapter_info; - while (adapter != 0) + + for (PIP_ADAPTER_INFO adapter = adapter_info; + adapter != 0; adapter = adapter->Next) { - if (interface == address::from_string(adapter->IpAddressList.IpAddress.String, ec)) + address iface = address::from_string(adapter->IpAddressList.IpAddress.String, ec); + if (ec) + { + ec = asio::error_code(); + continue; + } + if (is_loopback(iface) || is_any(iface)) continue; + if (interface == address() || interface == iface) { ret = address::from_string(adapter->GatewayList.IpAddress.String, ec); break; } - adapter = adapter->Next; } } diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index dbdba17f0..9bd02f3c4 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -334,6 +334,7 @@ namespace libtorrent { ++num_requested; blocks_requested = true; + TORRENT_ASSERT(i->info[k].num_peers > 0); } if (i->info[k].state == block_info::state_writing) { diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 2fdc5358a..0599096d5 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -294,6 +294,7 @@ namespace libtorrent || std::find(rq.begin(), rq.end(), *i) != rq.end()) continue; + TORRENT_ASSERT(p.num_peers(*i) > 0); busy_pieces.push_back(*i); continue; } @@ -333,6 +334,8 @@ namespace libtorrent p.piece_info(i->piece_index, st); TORRENT_ASSERT(st.requested + st.finished + st.writing == p.blocks_in_piece(i->piece_index)); #endif + TORRENT_ASSERT(p.is_requested(*i)); + TORRENT_ASSERT(p.num_peers(*i) > 0); c.add_request(*i); c.send_block_requests(); } diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index a93ad7cb0..a78507af0 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -617,6 +617,7 @@ namespace detail "\n"; m_buffer_usage_logger.open("buffer_stats.log", std::ios::trunc); m_second_counter = 0; + m_buffer_allocations = 0; #endif // ---- generate a peer id ---- @@ -797,12 +798,13 @@ namespace detail INVARIANT_CHECK; - TORRENT_ASSERT(s.connection_speed > 0); TORRENT_ASSERT(s.file_pool_size > 0); // less than 5 seconds unchoke interval is insane TORRENT_ASSERT(s.unchoke_interval >= 5); m_settings = s; + if (m_settings.connection_speed <= 0) m_settings.connection_speed = 200; + m_files.resize(m_settings.file_pool_size); // replace all occurances of '\n' with ' '. std::string::iterator i = m_settings.user_agent.begin(); @@ -959,12 +961,14 @@ namespace detail { // 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() + 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()); + if (i->interface_address.is_v4() + || i->interface_address.to_v6().is_link_local() + || i->interface_address.to_v6().is_loopback()) continue; + m_ipv6_interface = tcp::endpoint(i->interface_address, ep.port()); break; } break; @@ -2643,20 +2647,23 @@ namespace detail TORRENT_ASSERT(*slot_iter == p.index); int slot_index = static_cast(slot_iter - tmp_pieces.begin()); - unsigned long adler - = torrent_ptr->filesystem().piece_crc( - slot_index - , torrent_ptr->block_size() - , p.info); - - const entry& ad = (*i)["adler32"]; + const entry* ad = i->find_key("adler32"); - // crc's didn't match, don't use the resume data - if (ad.integer() != entry::integer_type(adler)) + if (ad && ad->type() == entry::int_t) { - error = "checksum mismatch on piece " - + boost::lexical_cast(p.index); - return; + unsigned long adler + = torrent_ptr->filesystem().piece_crc( + slot_index + , torrent_ptr->block_size() + , p.info); + + // crc's didn't match, don't use the resume data + if (ad->integer() != entry::integer_type(adler)) + { + error = "checksum mismatch on piece " + + boost::lexical_cast(p.index); + return; + } } tmp_unfinished.push_back(p); diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 2f3c7e7f9..810626f52 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -1151,7 +1151,7 @@ namespace libtorrent m_slot_to_piece.begin(); i != last.base(); ++i) { - p.push_back(have[*i] ? *i : unassigned); + p.push_back((*i >= 0 && have[*i]) ? *i : unassigned); } } else diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 635390537..bd893644d 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -569,7 +569,7 @@ namespace libtorrent TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1); } piece_struct["bitmask"] = bitmask; - +/* TORRENT_ASSERT(t->filesystem().slot_for(i->index) >= 0); unsigned long adler = t->filesystem().piece_crc( @@ -578,7 +578,7 @@ namespace libtorrent , i->info); piece_struct["adler32"] = adler; - +*/ // push the struct onto the unfinished-piece list up.push_back(piece_struct); } @@ -596,6 +596,8 @@ namespace libtorrent policy& pol = t->get_policy(); + int max_failcount = t->settings().max_failcount; + for (policy::iterator i = pol.begin_peer() , end(pol.end_peer()); i != end; ++i) { @@ -619,6 +621,9 @@ namespace libtorrent // been banned, don't save it. if (i->second.type == policy::peer::not_connectable) continue; + // don't save peers that doesn't work + if (i->second.failcount >= max_failcount) continue; + tcp::endpoint ip = i->second.ip; entry peer(entry::dictionary_t); peer["ip"] = ip.address().to_string(ec); diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index 4f6ac7fbf..5e9953fbc 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -76,27 +76,13 @@ upnp::upnp(io_service& ios, connection_queue& cc , m_refresh_timer(ios) , m_disabled(false) , m_closing(false) + , m_ignore_outside_network(ignore_nonrouters) , m_cc(cc) { #ifdef TORRENT_UPNP_LOGGING m_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc); #endif m_retry_count = 0; - - if (ignore_nonrouters) - { - asio::error_code ec; - std::vector
const& net = enum_net_interfaces(m_io_service, ec); - m_filter.reserve(net.size()); - for (std::vector
::const_iterator i = net.begin() - , end(net.end()); i != end; ++i) - { - asio::error_code e; - address a = router_for_interface(*i, e); - if (e || is_loopback(a)) continue; - m_filter.push_back(a); - } - } } upnp::~upnp() @@ -281,14 +267,29 @@ try Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 */ - if (!m_filter.empty() && std::find(m_filter.begin(), m_filter.end() - , from.address()) == m_filter.end()) + asio::error_code ec; + if (m_ignore_outside_network && !in_local_network(m_io_service, from.address(), ec)) { // this upnp device is filtered because it's not in the // list of configured routers #ifdef TORRENT_UPNP_LOGGING - m_log << time_now_string() << " <== (" << from << ") Rootdevice " - "ignored because it's not out router" << std::endl; + if (ec) + { + m_log << time_now_string() << " <== (" << from << ") error: " + << ec.message() << std::endl; + } + else + { + std::vector const& net = enum_net_interfaces(m_io_service, ec); + m_log << time_now_string() << " <== (" << from << ") UPnP device " + "ignored because it's not on our network "; + for (std::vector::const_iterator i = net.begin() + , end(net.end()); i != end; ++i) + { + m_log << "(" << i->interface_address << ", " << i->netmask << ") "; + } + m_log << std::endl; + } #endif return; }