2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2006-2016, Arvid Norberg
|
2003-10-23 01:00:57 +02:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2003-10-26 18:35:23 +01:00
|
|
|
#ifndef TORRENT_SESSION_HPP_INCLUDED
|
2003-10-23 01:00:57 +02:00
|
|
|
#define TORRENT_SESSION_HPP_INCLUDED
|
|
|
|
|
2016-05-01 00:54:23 +02:00
|
|
|
#include <thread>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-08-14 19:47:48 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
2012-03-19 03:43:06 +01:00
|
|
|
#include "libtorrent/build_config.hpp"
|
2015-06-03 05:04:44 +02:00
|
|
|
#include "libtorrent/io_service.hpp"
|
2016-07-28 20:57:26 +02:00
|
|
|
#include "libtorrent/settings_pack.hpp"
|
2015-07-08 05:32:35 +02:00
|
|
|
#include "libtorrent/session_handle.hpp"
|
2016-08-12 02:32:14 +02:00
|
|
|
#include "libtorrent/session_settings.hpp"
|
|
|
|
#include "libtorrent/kademlia/dht_storage.hpp"
|
2009-05-03 22:21:24 +02:00
|
|
|
|
2015-03-28 18:31:27 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2015-07-28 00:33:36 +02:00
|
|
|
#include "libtorrent/fingerprint.hpp"
|
2016-05-17 15:24:06 +02:00
|
|
|
#include <cstdio> // for snprintf
|
2015-03-28 18:31:27 +01:00
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
namespace libtorrent
|
|
|
|
{
|
2016-08-12 02:32:14 +02:00
|
|
|
struct plugin;
|
|
|
|
|
2014-02-02 06:09:18 +01:00
|
|
|
// The default values of the session settings are set for a regular
|
|
|
|
// bittorrent client running on a desktop system. There are functions that
|
|
|
|
// can set the session settings to pre set settings for other environments.
|
|
|
|
// These can be used for the basis, and should be tweaked to fit your needs
|
|
|
|
// better.
|
2013-08-08 04:57:07 +02:00
|
|
|
//
|
2014-02-02 06:09:18 +01:00
|
|
|
// ``min_memory_usage`` returns settings that will use the minimal amount of
|
|
|
|
// RAM, at the potential expense of upload and download performance. It
|
|
|
|
// adjusts the socket buffer sizes, disables the disk cache, lowers the send
|
|
|
|
// buffer watermarks so that each connection only has at most one block in
|
|
|
|
// use at any one time. It lowers the outstanding blocks send to the disk
|
|
|
|
// I/O thread so that connections only have one block waiting to be flushed
|
|
|
|
// to disk at any given time. It lowers the max number of peers in the peer
|
|
|
|
// list for torrents. It performs multiple smaller reads when it hashes
|
|
|
|
// pieces, instead of reading it all into memory before hashing.
|
2013-08-08 04:57:07 +02:00
|
|
|
//
|
2016-07-28 20:57:26 +02:00
|
|
|
// This configuration is intended to be the starting point for embedded
|
2014-02-02 06:09:18 +01:00
|
|
|
// devices. It will significantly reduce memory usage.
|
2013-08-08 04:57:07 +02:00
|
|
|
//
|
2014-02-02 06:09:18 +01:00
|
|
|
// ``high_performance_seed`` returns settings optimized for a seed box,
|
|
|
|
// serving many peers and that doesn't do any downloading. It has a 128 MB
|
|
|
|
// disk cache and has a limit of 400 files in its file pool. It support fast
|
|
|
|
// upload rates by allowing large send buffers.
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_EXPORT void min_memory_usage(settings_pack& set);
|
|
|
|
TORRENT_EXPORT void high_performance_seed(settings_pack& set);
|
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2015-04-17 03:49:49 +02:00
|
|
|
TORRENT_DEPRECATED
|
|
|
|
TORRENT_EXPORT session_settings min_memory_usage();
|
|
|
|
TORRENT_DEPRECATED
|
|
|
|
TORRENT_EXPORT session_settings high_performance_seed();
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2009-05-12 20:05:04 +02:00
|
|
|
|
2012-03-19 03:43:06 +01:00
|
|
|
#ifndef TORRENT_CFG
|
|
|
|
#error TORRENT_CFG is not defined!
|
|
|
|
#endif
|
|
|
|
|
2010-10-24 02:44:07 +02:00
|
|
|
void TORRENT_EXPORT TORRENT_CFG();
|
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
namespace aux
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-10-11 16:02:21 +02:00
|
|
|
struct session_impl;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2014-02-02 06:09:18 +01:00
|
|
|
// this is a holder for the internal session implementation object. Once the
|
|
|
|
// session destruction is explicitly initiated, this holder is used to
|
|
|
|
// synchronize the completion of the shutdown. The lifetime of this object
|
|
|
|
// may outlive session, causing the session destructor to not block. The
|
|
|
|
// session_proxy destructor will block however, until the underlying session
|
|
|
|
// is done shutting down.
|
2006-10-11 16:02:21 +02:00
|
|
|
class TORRENT_EXPORT session_proxy
|
|
|
|
{
|
|
|
|
friend class session;
|
2006-10-15 15:46:52 +02:00
|
|
|
public:
|
2013-12-19 06:35:47 +01:00
|
|
|
// default constructor, does not refer to any session
|
|
|
|
// implementation object.
|
2016-07-05 00:19:55 +02:00
|
|
|
session_proxy();
|
2015-06-03 05:04:44 +02:00
|
|
|
~session_proxy();
|
2016-07-05 00:19:55 +02:00
|
|
|
session_proxy(session_proxy const&);
|
|
|
|
session_proxy& operator=(session_proxy const&);
|
2006-10-11 16:02:21 +02:00
|
|
|
private:
|
2015-06-03 05:04:44 +02:00
|
|
|
session_proxy(
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<io_service> ios
|
2016-05-01 00:54:23 +02:00
|
|
|
, std::shared_ptr<std::thread> t
|
2016-09-01 03:42:18 +02:00
|
|
|
, std::shared_ptr<aux::session_impl> impl);
|
2016-07-05 00:19:55 +02:00
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<io_service> m_io_service;
|
2016-05-01 00:54:23 +02:00
|
|
|
std::shared_ptr<std::thread> m_thread;
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<aux::session_impl> m_impl;
|
2006-10-11 16:02:21 +02:00
|
|
|
};
|
2007-10-08 22:01:36 +02:00
|
|
|
|
2016-08-12 02:32:14 +02:00
|
|
|
// The session_params is a parameters pack for configuring the session
|
|
|
|
// before it's started.
|
|
|
|
struct TORRENT_EXPORT session_params
|
|
|
|
{
|
|
|
|
// This constructor can be used to start with the default plugins
|
|
|
|
// (ut_metadata, ut_pex and smart_ban). The default values in the
|
|
|
|
// settings is to start the default features like upnp, nat-pmp,
|
|
|
|
// and dht for example.
|
|
|
|
session_params(settings_pack sp = settings_pack());
|
|
|
|
// This constructor helps to configure the set of initial plugins
|
|
|
|
// to be added to the session before it's started.
|
|
|
|
session_params(settings_pack sp
|
2016-08-17 20:30:24 +02:00
|
|
|
, std::vector<std::shared_ptr<plugin>> exts);
|
2016-08-12 02:32:14 +02:00
|
|
|
|
|
|
|
session_params(session_params const&) = default;
|
|
|
|
session_params(session_params&&) = default;
|
|
|
|
session_params& operator=(session_params const&) = default;
|
|
|
|
session_params& operator=(session_params&&) = default;
|
|
|
|
|
|
|
|
settings_pack settings;
|
|
|
|
|
2016-08-17 20:30:24 +02:00
|
|
|
std::vector<std::shared_ptr<plugin>> extensions;
|
2016-08-12 02:32:14 +02:00
|
|
|
|
|
|
|
libtorrent::dht_settings dht_settings;
|
|
|
|
|
|
|
|
dht::dht_storage_constructor_type dht_storage_constructor;
|
|
|
|
};
|
|
|
|
|
2014-02-02 06:09:18 +01:00
|
|
|
// The session holds all state that spans multiple torrents. Among other
|
|
|
|
// things it runs the network loop and manages all torrents. Once it's
|
|
|
|
// created, the session object will spawn the main thread that will do all
|
|
|
|
// the work. The main thread will be idle as long it doesn't have any
|
|
|
|
// torrents to participate in.
|
2014-07-06 21:18:00 +02:00
|
|
|
//
|
|
|
|
// You have some control over session configuration through the
|
|
|
|
// ``session::apply_settings()`` member function. To change one or more
|
|
|
|
// configuration options, create a settings_pack. object and fill it with
|
|
|
|
// the settings to be set and pass it in to ``session::apply_settings()``.
|
|
|
|
//
|
|
|
|
// see apply_settings().
|
2016-07-05 00:19:55 +02:00
|
|
|
class TORRENT_EXPORT session : public session_handle
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
public:
|
2003-10-25 03:31:06 +02:00
|
|
|
|
2016-08-12 02:32:14 +02:00
|
|
|
// Constructs the session objects which acts as the container of torrents.
|
|
|
|
// In order to avoid a race condition between starting the session and
|
|
|
|
// configuring it, you can pass in a session_params object. Its settings
|
|
|
|
// will take effect before the session starts up.
|
|
|
|
session(session_params params = session_params())
|
|
|
|
: session_handle(nullptr)
|
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
|
|
|
start(std::move(params), nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overload of the constructor that takes an external io_service to run
|
|
|
|
// the session object on. This is primarily useful for tests that may want
|
|
|
|
// to run multiple sessions on a single io_service, or low resource
|
|
|
|
// systems where additional threads are expensive and sharing an
|
|
|
|
// io_service with other events is fine.
|
|
|
|
//
|
|
|
|
// .. warning::
|
|
|
|
// The session object does not cleanly terminate with an external
|
|
|
|
// ``io_service``. The ``io_service::run()`` call _must_ have returned
|
|
|
|
// before it's safe to destruct the session. Which means you *MUST*
|
|
|
|
// call session::abort() and save the session_proxy first, then
|
|
|
|
// destruct the session object, then sync with the io_service, then
|
|
|
|
// destruct the session_proxy object.
|
|
|
|
session(session_params params, io_service& ios)
|
|
|
|
: session_handle(nullptr)
|
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
|
|
|
start(std::move(params), &ios);
|
|
|
|
}
|
|
|
|
|
2016-07-28 20:57:26 +02:00
|
|
|
// Constructs the session objects which acts as the container of torrents.
|
2015-06-03 05:04:44 +02:00
|
|
|
// It provides configuration options across torrents (such as rate limits,
|
|
|
|
// disk cache, ip filter etc.). In order to avoid a race condition between
|
|
|
|
// starting the session and configuring it, you can pass in a
|
|
|
|
// settings_pack object. Its settings will take effect before the session
|
|
|
|
// starts up.
|
2014-02-02 06:09:18 +01:00
|
|
|
//
|
2015-06-03 05:04:44 +02:00
|
|
|
// The ``flags`` parameter can be used to start default features (upnp &
|
2014-02-02 06:09:18 +01:00
|
|
|
// nat-pmp) and default plugins (ut_metadata, ut_pex and smart_ban). The
|
2014-07-06 21:18:00 +02:00
|
|
|
// default is to start those features. If you do not want them to start,
|
2014-02-02 06:09:18 +01:00
|
|
|
// pass 0 as the flags parameter.
|
2016-08-12 02:32:14 +02:00
|
|
|
session(settings_pack pack
|
2015-06-03 05:04:44 +02:00
|
|
|
, int flags = start_default_features | add_default_plugins)
|
2016-06-20 17:32:06 +02:00
|
|
|
: session_handle(nullptr)
|
2015-06-03 05:04:44 +02:00
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
2016-06-20 17:32:06 +02:00
|
|
|
start(flags, pack, nullptr);
|
2015-06-03 05:04:44 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-07-05 00:19:55 +02:00
|
|
|
// moveable
|
|
|
|
session(session&&) = default;
|
|
|
|
session& operator=(session&&) = default;
|
|
|
|
|
|
|
|
// noncopyable
|
|
|
|
session(session const&) = delete;
|
|
|
|
session& operator=(session const&) = delete;
|
|
|
|
|
2015-06-03 05:04:44 +02:00
|
|
|
// overload of the constructor that takes an external io_service to run
|
|
|
|
// the session object on. This is primarily useful for tests that may want
|
|
|
|
// to run multiple sessions on a single io_service, or low resource
|
|
|
|
// systems where additional threads are expensive and sharing an
|
|
|
|
// io_service with other events is fine.
|
|
|
|
//
|
|
|
|
// .. warning::
|
|
|
|
// The session object does not cleanly terminate with an external
|
2015-07-12 05:01:27 +02:00
|
|
|
// ``io_service``. The ``io_service::run()`` call _must_ have returned
|
|
|
|
// before it's safe to destruct the session. Which means you *MUST*
|
|
|
|
// call session::abort() and save the session_proxy first, then
|
|
|
|
// destruct the session object, then sync with the io_service, then
|
|
|
|
// destruct the session_proxy object.
|
2016-08-05 06:28:03 +02:00
|
|
|
session(settings_pack pack
|
2015-06-03 05:04:44 +02:00
|
|
|
, io_service& ios
|
2014-07-06 21:18:00 +02:00
|
|
|
, int flags = start_default_features | add_default_plugins)
|
2016-06-20 17:32:06 +02:00
|
|
|
: session_handle(nullptr)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
2015-06-03 05:04:44 +02:00
|
|
|
start(flags, pack, &ios);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-06-03 05:04:44 +02:00
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
TORRENT_DEPRECATED
|
2015-06-05 08:38:07 +02:00
|
|
|
session(fingerprint const& print
|
2008-09-22 01:19:58 +02:00
|
|
|
, int flags = start_default_features | add_default_plugins
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint32_t alert_mask = alert::error_notification)
|
2016-06-20 17:32:06 +02:00
|
|
|
: session_handle(nullptr)
|
2010-10-24 02:44:07 +02:00
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack pack;
|
|
|
|
pack.set_int(settings_pack::alert_mask, alert_mask);
|
2014-12-31 16:51:45 +01:00
|
|
|
pack.set_str(settings_pack::peer_fingerprint, print.to_string());
|
2014-07-06 21:18:00 +02:00
|
|
|
if ((flags & start_default_features) == 0)
|
|
|
|
{
|
|
|
|
pack.set_bool(settings_pack::enable_upnp, false);
|
|
|
|
pack.set_bool(settings_pack::enable_natpmp, false);
|
|
|
|
pack.set_bool(settings_pack::enable_lsd, false);
|
|
|
|
pack.set_bool(settings_pack::enable_dht, false);
|
|
|
|
}
|
|
|
|
|
2016-08-05 06:28:03 +02:00
|
|
|
start(flags, std::move(pack), nullptr);
|
2010-10-24 02:44:07 +02:00
|
|
|
}
|
2015-06-03 05:04:44 +02:00
|
|
|
|
|
|
|
TORRENT_DEPRECATED
|
2013-07-20 22:11:01 +02:00
|
|
|
session(fingerprint const& print
|
2004-03-29 00:44:40 +02:00
|
|
|
, std::pair<int, int> listen_port_range
|
2007-11-16 22:21:28 +01:00
|
|
|
, char const* listen_interface = "0.0.0.0"
|
2008-09-22 01:19:58 +02:00
|
|
|
, int flags = start_default_features | add_default_plugins
|
2014-12-09 10:08:26 +01:00
|
|
|
, int alert_mask = alert::error_notification)
|
2016-06-20 17:32:06 +02:00
|
|
|
: session_handle(nullptr)
|
2010-10-24 02:44:07 +02:00
|
|
|
{
|
|
|
|
TORRENT_CFG();
|
|
|
|
TORRENT_ASSERT(listen_port_range.first > 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(listen_port_range.first <= listen_port_range.second);
|
|
|
|
|
|
|
|
settings_pack pack;
|
|
|
|
pack.set_int(settings_pack::alert_mask, alert_mask);
|
|
|
|
pack.set_int(settings_pack::max_retry_port_bind, listen_port_range.second - listen_port_range.first);
|
2014-12-31 16:51:45 +01:00
|
|
|
pack.set_str(settings_pack::peer_fingerprint, print.to_string());
|
2014-07-06 21:18:00 +02:00
|
|
|
char if_string[100];
|
2016-02-03 05:17:51 +01:00
|
|
|
|
2016-06-20 17:32:06 +02:00
|
|
|
if (listen_interface == nullptr) listen_interface = "0.0.0.0";
|
2016-05-17 15:24:06 +02:00
|
|
|
std::snprintf(if_string, sizeof(if_string), "%s:%d", listen_interface, listen_port_range.first);
|
2014-07-06 21:18:00 +02:00
|
|
|
pack.set_str(settings_pack::listen_interfaces, if_string);
|
|
|
|
|
|
|
|
if ((flags & start_default_features) == 0)
|
|
|
|
{
|
|
|
|
pack.set_bool(settings_pack::enable_upnp, false);
|
|
|
|
pack.set_bool(settings_pack::enable_natpmp, false);
|
|
|
|
pack.set_bool(settings_pack::enable_lsd, false);
|
|
|
|
pack.set_bool(settings_pack::enable_dht, false);
|
|
|
|
}
|
2016-08-05 06:28:03 +02:00
|
|
|
start(flags, std::move(pack), nullptr);
|
2010-10-24 02:44:07 +02:00
|
|
|
}
|
2015-06-03 05:04:44 +02:00
|
|
|
#endif // TORRENT_NO_DEPRECATE
|
2015-05-30 19:41:38 +02:00
|
|
|
|
2014-02-02 06:09:18 +01:00
|
|
|
// The destructor of session will notify all trackers that our torrents
|
|
|
|
// have been shut down. If some trackers are down, they will time out.
|
|
|
|
// All this before the destructor of session returns. So, it's advised
|
|
|
|
// that any kind of interface (such as windows) are closed before
|
|
|
|
// destructing the session object. Because it can take a few second for
|
2014-07-06 21:18:00 +02:00
|
|
|
// it to finish. The timeout can be set with apply_settings().
|
2003-10-23 01:00:57 +02:00
|
|
|
~session();
|
|
|
|
|
2016-02-10 17:58:09 +01:00
|
|
|
// In case you want to destruct the session asynchronously, you can
|
2014-02-02 06:09:18 +01:00
|
|
|
// request a session destruction proxy. If you don't do this, the
|
|
|
|
// destructor of the session object will block while the trackers are
|
|
|
|
// contacted. If you keep one ``session_proxy`` to the session when
|
|
|
|
// destructing it, the destructor will not block, but start to close down
|
|
|
|
// the session, the destructor of the proxy will then synchronize the
|
|
|
|
// threads. So, the destruction of the session is performed from the
|
|
|
|
// ``session`` destructor call until the ``session_proxy`` destructor
|
|
|
|
// call. The ``session_proxy`` does not have any operations on it (since
|
|
|
|
// the session is being closed down, no operations are allowed on it).
|
|
|
|
// The only valid operation is calling the destructor::
|
2013-07-20 22:11:01 +02:00
|
|
|
//
|
|
|
|
// class session_proxy
|
|
|
|
// {
|
|
|
|
// public:
|
|
|
|
// session_proxy();
|
|
|
|
// ~session_proxy()
|
|
|
|
// };
|
2016-08-20 17:04:44 +02:00
|
|
|
session_proxy abort();
|
2006-10-11 16:02:21 +02:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
private:
|
|
|
|
|
2016-08-12 02:32:14 +02:00
|
|
|
void start(session_params params, io_service* ios);
|
|
|
|
void start(int flags, settings_pack sp, io_service* ios);
|
2010-10-24 02:44:07 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
// data shared between the main thread
|
|
|
|
// and the working thread
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<io_service> m_io_service;
|
2016-05-01 00:54:23 +02:00
|
|
|
std::shared_ptr<std::thread> m_thread;
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<aux::session_impl> m_impl;
|
2003-10-23 01:00:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TORRENT_SESSION_HPP_INCLUDED
|