the file pool has been moved to the session and its size can be controlled via session_settings. Added untested option to allow multiple connections from the same IP.

This commit is contained in:
Arvid Norberg
2006-11-14 15:53:38 +00:00
parent 247b8ae443
commit 51e3261dd0
16 changed files with 172 additions and 83 deletions

View File

@@ -1,3 +1,5 @@
* moved the file_pool into session. The number of open files is now
limited per session.
* fixed uninitialized private flag in torrent_info * fixed uninitialized private flag in torrent_info
* fixed long standing issue with file.cpp on windows. Replaced the low level * fixed long standing issue with file.cpp on windows. Replaced the low level
io functions used on windows. io functions used on windows.

View File

@@ -180,6 +180,7 @@ int main(int argc, char* argv[])
#include "libtorrent/file.hpp" #include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/file_pool.hpp"
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
@@ -188,7 +189,10 @@ int main(int argc, char* argv[])
using namespace boost::filesystem; using namespace boost::filesystem;
using namespace libtorrent; using namespace libtorrent;
void add_files(torrent_info& t, path const& p, path const& l) void add_files(
torrent_info& t
, path const& p
, path const& l)
{ {
path f(p / l); path f(p / l);
if (is_directory(f)) if (is_directory(f))
@@ -199,10 +203,7 @@ void add_files(torrent_info& t, path const& p, path const& l)
else else
{ {
std::cerr << "adding \"" << l.string() << "\"\n"; std::cerr << "adding \"" << l.string() << "\"\n";
file fi(f, file::in); t.add_file(l, file_size(f));
fi.seek(0, file::end);
libtorrent::size_type size = fi.tell();
t.add_file(l, size);
} }
} }
@@ -211,6 +212,8 @@ int main(int argc, char* argv[])
using namespace libtorrent; using namespace libtorrent;
using namespace boost::filesystem; using namespace boost::filesystem;
path::default_name_check(no_check);
if (argc != 4) if (argc != 4)
{ {
std::cerr << "usage: make_torrent <output torrent-file> " std::cerr << "usage: make_torrent <output torrent-file> "
@@ -218,13 +221,11 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
boost::filesystem::path::default_name_check(native);
try try
{ {
torrent_info t; torrent_info t;
path full_path = initial_path() / path(argv[3]); path full_path = complete(path(argv[3]));
ofstream out(initial_path() / path(argv[1]), std::ios_base::binary); ofstream out(complete(path(argv[1])), std::ios_base::binary);
int piece_size = 256 * 1024; int piece_size = 256 * 1024;
char const* creator_str = "libtorrent"; char const* creator_str = "libtorrent";
@@ -232,7 +233,8 @@ int main(int argc, char* argv[])
add_files(t, full_path.branch_path(), full_path.leaf()); add_files(t, full_path.branch_path(), full_path.leaf());
t.set_piece_size(piece_size); t.set_piece_size(piece_size);
storage st(t, full_path.branch_path()); file_pool fp;
storage st(t, full_path.branch_path(), fp);
t.add_tracker(argv[2]); t.add_tracker(argv[2]);
// calculate the hash for all pieces // calculate the hash for all pieces
@@ -251,8 +253,8 @@ int main(int argc, char* argv[])
// create the torrent and print it to out // create the torrent and print it to out
entry e = t.create_torrent(); entry e = t.create_torrent();
libtorrent::bencode(std::ostream_iterator<char>(out), e); libtorrent::bencode(std::ostream_iterator<char>(out), e);
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::cerr << e.what() << "\n"; std::cerr << e.what() << "\n";
} }

View File

@@ -158,22 +158,26 @@ Shows how to create a torrent from a directory tree::
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <iomanip> #include <iomanip>
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/file.hpp" #include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/file_pool.hpp"
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
using namespace boost::filesystem; using namespace boost::filesystem;
using namespace libtorrent; using namespace libtorrent;
void add_files(torrent_info& t, path const& p, path const& l) void add_files(
torrent_info& t
, path const& p
, path const& l)
{ {
path f(p / l); path f(p / l);
if (is_directory(f)) if (is_directory(f))
@@ -184,42 +188,40 @@ Shows how to create a torrent from a directory tree::
else else
{ {
std::cerr << "adding \"" << l.string() << "\"\n"; std::cerr << "adding \"" << l.string() << "\"\n";
file fi(f, file::in); t.add_file(l, file_size(f));
fi.seek(0, file::end);
libtorrent::size_type size = fi.tell();
t.add_file(l, size);
} }
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
using namespace libtorrent; using namespace libtorrent;
using namespace boost::filesystem; using namespace boost::filesystem;
path::default_name_check(no_check);
if (argc != 4) if (argc != 4)
{ {
std::cerr << "usage: make_torrent <output torrent-file> " std::cerr << "usage: make_torrent <output torrent-file> "
"<announce url> <file or directory to create torrent from>\n"; "<announce url> <file or directory to create torrent from>\n";
return 1; return 1;
} }
boost::filesystem::path::default_name_check(native);
try try
{ {
torrent_info t; torrent_info t;
path full_path = initial_path() / path(argv[3]); path full_path = complete(path(argv[3]));
ofstream out(initial_path() / path(argv[1]), std::ios_base::binary); ofstream out(complete(path(argv[1])), std::ios_base::binary);
int piece_size = 256 * 1024; int piece_size = 256 * 1024;
char const* creator_str = "libtorrent"; char const* creator_str = "libtorrent";
add_files(t, full_path.branch_path(), full_path.leaf()); add_files(t, full_path.branch_path(), full_path.leaf());
t.set_piece_size(piece_size); t.set_piece_size(piece_size);
storage st(t, full_path.branch_path()); file_pool fp;
storage st(t, full_path.branch_path(), fp);
t.add_tracker(argv[2]); t.add_tracker(argv[2]);
// calculate the hash for all pieces // calculate the hash for all pieces
int num = t.num_pieces(); int num = t.num_pieces();
std::vector<char> buf(piece_size); std::vector<char> buf(piece_size);
@@ -230,19 +232,19 @@ Shows how to create a torrent from a directory tree::
t.set_hash(i, h.final()); t.set_hash(i, h.final());
std::cerr << (i+1) << "/" << num << "\r"; std::cerr << (i+1) << "/" << num << "\r";
} }
t.set_creator(creator_str); t.set_creator(creator_str);
// create the torrent and print it to out // create the torrent and print it to out
entry e = t.create_torrent(); entry e = t.create_torrent();
libtorrent::bencode(std::ostream_iterator<char>(out), e); libtorrent::bencode(std::ostream_iterator<char>(out), e);
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::cerr << e.what() << "\n"; std::cerr << e.what() << "\n";
} }
return 0; return 0;
} }

View File

@@ -1913,6 +1913,8 @@ struct session_settings
int peer_timeout; int peer_timeout;
int urlseed_timeout; int urlseed_timeout;
int urlseed_pipeline_size; int urlseed_pipeline_size;
int file_pool_size;
bool allow_multiple_connections_per_ip;
}; };
</pre> </pre>
<p><tt class="docutils literal"><span class="pre">proxy_ip</span></tt> may be a hostname or ip to a http proxy to use. If this is <p><tt class="docutils literal"><span class="pre">proxy_ip</span></tt> may be a hostname or ip to a http proxy to use. If this is
@@ -1973,6 +1975,20 @@ url seeds. This value defaults to 20 seconds.</p>
using persistent connections to HTTP 1.1 servers, the client is allowed to using persistent connections to HTTP 1.1 servers, the client is allowed to
send more requests before the first response is received. This number controls send more requests before the first response is received. This number controls
the number of outstanding requests to use with url-seeds. Default is 5.</p> the number of outstanding requests to use with url-seeds. Default is 5.</p>
<p><tt class="docutils literal"><span class="pre">file_pool_size</span></tt> is the the upper limit on the total number of files this
session will keep open. The reason why files are left open at all is that
some anti virus software hooks on every file close, and scans the file for
viruses. deferring the closing of the files will be the difference between
a usable system and a completely hogged down system. Most operating systems
also has a limit on the total number of file descriptors a process may have
open. It is usually a good idea to find this limit and set the number of
connections and the number of files limits so their sum is slightly below it.</p>
<p><tt class="docutils literal"><span class="pre">allow_multiple_connections_per_ip</span></tt> determines if connections from the
same IP address as existing connections should be rejected or not. Multiple
connections from the same IP address is not allowed by default, to prevent
abusive behavior by peers. It may be useful to allow such connections in
cases where simulations are run on the same machie, and all peers in a
swarm has the same IP address.</p>
</div> </div>
<div class="section" id="ip-filter"> <div class="section" id="ip-filter">
<h1><a name="ip-filter">ip_filter</a></h1> <h1><a name="ip-filter">ip_filter</a></h1>

View File

@@ -1894,6 +1894,8 @@ that will be sent to the tracker. The user-agent is a good way to identify your
int peer_timeout; int peer_timeout;
int urlseed_timeout; int urlseed_timeout;
int urlseed_pipeline_size; int urlseed_pipeline_size;
int file_pool_size;
bool allow_multiple_connections_per_ip;
}; };
``proxy_ip`` may be a hostname or ip to a http proxy to use. If this is ``proxy_ip`` may be a hostname or ip to a http proxy to use. If this is
@@ -1970,6 +1972,22 @@ using persistent connections to HTTP 1.1 servers, the client is allowed to
send more requests before the first response is received. This number controls send more requests before the first response is received. This number controls
the number of outstanding requests to use with url-seeds. Default is 5. the number of outstanding requests to use with url-seeds. Default is 5.
``file_pool_size`` is the the upper limit on the total number of files this
session will keep open. The reason why files are left open at all is that
some anti virus software hooks on every file close, and scans the file for
viruses. deferring the closing of the files will be the difference between
a usable system and a completely hogged down system. Most operating systems
also has a limit on the total number of file descriptors a process may have
open. It is usually a good idea to find this limit and set the number of
connections and the number of files limits so their sum is slightly below it.
``allow_multiple_connections_per_ip`` determines if connections from the
same IP address as existing connections should be rejected or not. Multiple
connections from the same IP address is not allowed by default, to prevent
abusive behavior by peers. It may be useful to allow such connections in
cases where simulations are run on the same machie, and all peers in a
swarm has the same IP address.
ip_filter ip_filter
========= =========

View File

@@ -1,6 +1,6 @@
/* /*
Copyright (c) 2003, Arvid Norberg Copyright (c) 2006, 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
@@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/file.hpp" #include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/file_pool.hpp"
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
@@ -94,7 +95,8 @@ int main(int argc, char* argv[])
add_files(t, full_path.branch_path(), full_path.leaf()); add_files(t, full_path.branch_path(), full_path.leaf());
t.set_piece_size(piece_size); t.set_piece_size(piece_size);
storage st(t, full_path.branch_path()); file_pool fp;
storage st(t, full_path.branch_path(), fp);
t.add_tracker(argv[2]); t.add_tracker(argv[2]);
// calculate the hash for all pieces // calculate the hash for all pieces

View File

@@ -75,6 +75,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/session_status.hpp" #include "libtorrent/session_status.hpp"
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "libtorrent/stat.hpp" #include "libtorrent/stat.hpp"
#include "libtorrent/file_pool.hpp"
namespace libtorrent namespace libtorrent
{ {
@@ -338,6 +339,11 @@ namespace libtorrent
// this is used to know if the client is behind // this is used to know if the client is behind
// NAT or not. // NAT or not.
bool m_incoming_connection; bool m_incoming_connection;
// the file pool that all storages in this session's
// torrents uses. It sets a limit on the number of
// open files by this session.
file_pool m_files;
// does the actual disconnections // does the actual disconnections
// that are queued up in m_disconnect_peer // that are queued up in m_disconnect_peer

View File

@@ -63,10 +63,11 @@ namespace libtorrent
struct file_pool struct file_pool
{ {
file_pool(int size): m_size(size) {} file_pool(int size = 40): m_size(size) {}
boost::shared_ptr<file> open_file(void* st, fs::path const& p, file::open_mode m); boost::shared_ptr<file> open_file(void* st, fs::path const& p, file::open_mode m);
void release(void* st); void release(void* st);
void resize(int size);
private: private:
int m_size; int m_size;

View File

@@ -56,6 +56,8 @@ namespace libtorrent
, peer_timeout(120) , peer_timeout(120)
, urlseed_timeout(20) , urlseed_timeout(20)
, urlseed_pipeline_size(5) , urlseed_pipeline_size(5)
, file_pool_size(40)
, allow_multiple_connections_per_ip(false)
{} {}
std::string proxy_ip; std::string proxy_ip;
@@ -130,6 +132,24 @@ namespace libtorrent
// controls the pipelining size of url-seeds // controls the pipelining size of url-seeds
int urlseed_pipeline_size; int urlseed_pipeline_size;
// sets the upper limit on the total number of files this
// session will keep open. The reason why files are
// left open at all is that some anti virus software
// hooks on every file close, and scans the file for
// viruses. deferring the closing of the files will
// be the difference between a usable system and
// a completely hogged down system. Most operating
// systems also has a limit on the total number of
// file descriptors a process may have open. It is
// usually a good idea to find this limit and set the
// number of connections and the number of files
// limits so their sum is slightly below it.
int file_pool_size;
// false to not allow multiple connections from the same
// IP address. true will allow it.
bool allow_multiple_connections_per_ip;
}; };
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT

View File

@@ -61,6 +61,7 @@ namespace libtorrent
} }
class session; class session;
class file_pool;
#if defined(_WIN32) && defined(UNICODE) #if defined(_WIN32) && defined(UNICODE)
@@ -91,7 +92,8 @@ namespace libtorrent
public: public:
storage( storage(
const torrent_info& info const torrent_info& info
, const boost::filesystem::path& path); , const boost::filesystem::path& path
, file_pool& fp);
void swap(storage&); void swap(storage&);
@@ -125,7 +127,8 @@ namespace libtorrent
piece_manager( piece_manager(
const torrent_info& info const torrent_info& info
, const boost::filesystem::path& path); , const boost::filesystem::path& path
, file_pool& fp);
~piece_manager(); ~piece_manager();

View File

@@ -1203,7 +1203,7 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " received invalid info_hash\n"; (*m_logger) << " received invalid info_hash\n";
#endif #endif
throw std::runtime_error("invalid info-hash in handshake"); throw protocol_error("invalid info-hash in handshake");
} }
} }
@@ -1279,13 +1279,6 @@ namespace libtorrent
if (m_supports_extensions) write_extensions(); if (m_supports_extensions) write_extensions();
#endif #endif
/*
if (!m_active)
{
m_attached_to_torrent = true;
assert(m_torrent->get_policy().has_connection(this));
}
*/
m_state = read_packet_size; m_state = read_packet_size;
reset_recv_buffer(4); reset_recv_buffer(4);
} }

View File

@@ -101,4 +101,23 @@ namespace libtorrent
kt.erase(start, end); kt.erase(start, end);
} }
void file_pool::resize(int size)
{
assert(size > 0);
if (size == m_size) return;
m_size = size;
if (int(m_files.size()) <= m_size) return;
// close the least recently used files
typedef nth_index<file_set, 1>::type lru_view;
lru_view& lt = get<1>(m_files);
lru_view::iterator i = lt.begin();
while (int(m_files.size()) > m_size)
{
// the first entry in this view is the least recently used
assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
lt.erase(i++);
}
}
} }

View File

@@ -871,21 +871,9 @@ namespace libtorrent
void policy::new_connection(peer_connection& c) void policy::new_connection(peer_connection& c)
{ {
assert(!c.is_local()); assert(!c.is_local());
/*
#ifndef NDEBUG
// avoid the invariant check to fail
peer p(tcp::endpoint("0.0.0.0", 0), peer::not_connectable);
p.connection = &c;
m_peers.push_back(p);
#endif
*/
INVARIANT_CHECK; INVARIANT_CHECK;
/*
#ifndef NDEBUG
// avoid the invariant check to fail
m_peers.erase(m_peers.end() - 1);
#endif
*/
// if the connection comes from the tracker, // if the connection comes from the tracker,
// it's probably just a NAT-check. Ignore the // it's probably just a NAT-check. Ignore the
// num connections constraint then. // num connections constraint then.
@@ -908,11 +896,19 @@ namespace libtorrent
} }
#endif #endif
std::vector<peer>::iterator i = std::find_if( std::vector<peer>::iterator i;
m_peers.begin()
, m_peers.end()
, match_peer_ip(c.remote()));
if (m_torrent->settings().allow_multiple_connections_per_ip)
{
i = m_peers.end();
}
else
{
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_ip(c.remote()));
}
if (i != m_peers.end()) if (i != m_peers.end())
{ {
@@ -1322,7 +1318,7 @@ namespace libtorrent
return std::find_if( return std::find_if(
m_peers.begin() m_peers.begin()
, m_peers.end() , m_peers.end()
, match_peer_ip(c->remote())) != m_peers.end(); , match_peer_connection(*c)) != m_peers.end();
} }
void policy::check_invariant() const void policy::check_invariant() const

View File

@@ -475,6 +475,7 @@ namespace libtorrent { namespace detail
, m_max_connections(-1) , m_max_connections(-1)
, m_half_open_limit(-1) , m_half_open_limit(-1)
, m_incoming_connection(false) , m_incoming_connection(false)
, m_files(40)
, m_last_tick(microsec_clock::universal_time()) , m_last_tick(microsec_clock::universal_time())
, m_timer(m_selector) , m_timer(m_selector)
, m_checker_impl(*this) , m_checker_impl(*this)
@@ -575,6 +576,7 @@ namespace libtorrent { namespace detail
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
m_settings = s; m_settings = s;
m_files.resize(m_settings.file_pool_size);
// replace all occurances of '\n' with ' '. // replace all occurances of '\n' with ' '.
std::string::iterator i = m_settings.user_agent.begin(); std::string::iterator i = m_settings.user_agent.begin();
while ((i = std::find(i, m_settings.user_agent.end(), '\n')) while ((i = std::find(i, m_settings.user_agent.end(), '\n'))

View File

@@ -342,9 +342,10 @@ namespace libtorrent
class storage::impl : public thread_safe_storage, boost::noncopyable class storage::impl : public thread_safe_storage, boost::noncopyable
{ {
public: public:
impl(torrent_info const& info, path const& path) impl(torrent_info const& info, path const& path, file_pool& fp)
: thread_safe_storage(info.num_pieces()) : thread_safe_storage(info.num_pieces())
, info(info) , info(info)
, files(fp)
{ {
save_path = complete(path); save_path = complete(path);
assert(save_path.is_complete()); assert(save_path.is_complete());
@@ -354,6 +355,7 @@ namespace libtorrent
: thread_safe_storage(x.info.num_pieces()) : thread_safe_storage(x.info.num_pieces())
, info(x.info) , info(x.info)
, save_path(x.save_path) , save_path(x.save_path)
, files(x.files)
{} {}
~impl() ~impl()
@@ -363,13 +365,15 @@ namespace libtorrent
torrent_info const& info; torrent_info const& info;
path save_path; path save_path;
static file_pool files; // the file pool is typically stored in
// the session, to make all storage
// instances use the same pool
file_pool& files;
}; };
file_pool storage::impl::files(40); storage::storage(torrent_info const& info, path const& path
, file_pool& fp)
storage::storage(torrent_info const& info, path const& path) : m_pimpl(new impl(info, path, fp))
: m_pimpl(new impl(info, path))
{ {
assert(info.begin_files() != info.end_files()); assert(info.begin_files() != info.end_files());
} }
@@ -735,7 +739,8 @@ namespace libtorrent
impl( impl(
torrent_info const& info torrent_info const& info
, path const& path); , path const& path
, file_pool& fp);
bool check_fastresume( bool check_fastresume(
aux::piece_checker_data& d aux::piece_checker_data& d
@@ -884,8 +889,9 @@ namespace libtorrent
piece_manager::impl::impl( piece_manager::impl::impl(
torrent_info const& info torrent_info const& info
, path const& save_path) , path const& save_path
: m_storage(info, save_path) , file_pool& fp)
: m_storage(info, save_path, fp)
, m_compact_mode(false) , m_compact_mode(false)
, m_fill_mode(true) , m_fill_mode(true)
, m_info(info) , m_info(info)
@@ -897,8 +903,9 @@ namespace libtorrent
piece_manager::piece_manager( piece_manager::piece_manager(
torrent_info const& info torrent_info const& info
, path const& save_path) , path const& save_path
: m_pimpl(new impl(info, save_path)) , file_pool& fp)
: m_pimpl(new impl(info, save_path, fp))
{ {
} }

View File

@@ -431,7 +431,7 @@ namespace libtorrent
assert(m_torrent_file.total_size() >= 0); assert(m_torrent_file.total_size() >= 0);
m_have_pieces.resize(m_torrent_file.num_pieces(), false); m_have_pieces.resize(m_torrent_file.num_pieces(), false);
m_storage.reset(new piece_manager(m_torrent_file, m_save_path)); m_storage.reset(new piece_manager(m_torrent_file, m_save_path, m_ses.m_files));
m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); m_block_size = calculate_block_size(m_torrent_file, m_default_block_size);
m_picker.reset(new piece_picker( m_picker.reset(new piece_picker(
static_cast<int>(m_torrent_file.piece_length() / m_block_size) static_cast<int>(m_torrent_file.piece_length() / m_block_size)