2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
2003-12-14 06:56:12 +01:00
|
|
|
Copyright (c) 2003, Arvid Norberg, Magnus Jonsson
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctime>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
2003-10-25 03:31:06 +02:00
|
|
|
#include <cctype>
|
2003-10-27 16:43:33 +01:00
|
|
|
#include <algorithm>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push, 1)
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/filesystem/convenience.hpp>
|
2003-11-28 18:29:27 +01:00
|
|
|
#include <boost/filesystem/exception.hpp>
|
2003-12-15 18:46:47 +01:00
|
|
|
#include <boost/limits.hpp>
|
2004-01-17 21:04:19 +01:00
|
|
|
#include <boost/bind.hpp>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/peer_id.hpp"
|
|
|
|
#include "libtorrent/torrent_info.hpp"
|
2004-01-31 11:46:15 +01:00
|
|
|
#include "libtorrent/tracker_manager.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/session.hpp"
|
2003-12-16 14:33:29 +01:00
|
|
|
#include "libtorrent/fingerprint.hpp"
|
2004-01-07 01:48:02 +01:00
|
|
|
#include "libtorrent/entry.hpp"
|
2004-01-18 20:12:18 +01:00
|
|
|
#include "libtorrent/alert_types.hpp"
|
2004-01-25 19:18:36 +01:00
|
|
|
#include "libtorrent/invariant_check.hpp"
|
2004-01-26 02:08:59 +01:00
|
|
|
#include "libtorrent/file.hpp"
|
2004-02-12 15:41:39 +01:00
|
|
|
#include "libtorrent/allocate_resources.hpp"
|
2006-04-25 23:04:48 +02:00
|
|
|
#include "libtorrent/bt_peer_connection.hpp"
|
2005-07-06 02:58:23 +02:00
|
|
|
#include "libtorrent/ip_filter.hpp"
|
2006-04-25 23:04:48 +02:00
|
|
|
#include "libtorrent/socket.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-10-14 03:17:04 +02:00
|
|
|
using namespace boost::posix_time;
|
2006-04-25 23:04:48 +02:00
|
|
|
using boost::shared_ptr;
|
|
|
|
using boost::weak_ptr;
|
|
|
|
using boost::bind;
|
|
|
|
using boost::mutex;
|
|
|
|
using libtorrent::detail::session_impl;
|
2004-10-14 03:17:04 +02:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
namespace libtorrent { namespace detail
|
2003-10-26 18:35:23 +01:00
|
|
|
{
|
2004-03-05 13:04:47 +01:00
|
|
|
|
2005-02-23 10:13:42 +01:00
|
|
|
std::string generate_auth_string(std::string const& user
|
|
|
|
, std::string const& passwd)
|
|
|
|
{
|
|
|
|
if (user.empty()) return std::string();
|
|
|
|
return user + ":" + passwd;
|
|
|
|
}
|
|
|
|
|
2004-03-05 13:04:47 +01:00
|
|
|
// This is the checker thread
|
|
|
|
// it is looping in an infinite loop
|
|
|
|
// until the session is aborted. It will
|
|
|
|
// normally just block in a wait() call,
|
|
|
|
// waiting for a signal from session that
|
|
|
|
// there's a new torrent to check.
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
void checker_impl::operator()()
|
2003-10-26 18:35:23 +01:00
|
|
|
{
|
2004-02-26 13:59:01 +01:00
|
|
|
eh_initializer();
|
2005-10-13 09:59:05 +02:00
|
|
|
// if we're currently performing a full file check,
|
|
|
|
// this is the torrent being processed
|
|
|
|
boost::shared_ptr<piece_checker_data> processing;
|
|
|
|
boost::shared_ptr<piece_checker_data> t;
|
2004-02-26 13:59:01 +01:00
|
|
|
for (;;)
|
2003-10-31 05:02:51 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
// temporary torrent used while checking fastresume data
|
|
|
|
try
|
2003-10-31 05:02:51 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
t.reset();
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock l(m_mutex);
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
// if the job queue is empty and
|
|
|
|
// we shouldn't abort
|
|
|
|
// wait for a signal
|
|
|
|
if (m_torrents.empty() && !m_abort && !processing)
|
|
|
|
m_cond.wait(l);
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
if (m_abort)
|
|
|
|
{
|
|
|
|
// no lock is needed here, because the main thread
|
|
|
|
// has already been shut down by now
|
|
|
|
processing.reset();
|
|
|
|
t.reset();
|
|
|
|
std::for_each(m_torrents.begin(), m_torrents.end()
|
|
|
|
, boost::bind(&torrent::abort
|
|
|
|
, boost::bind(&shared_ptr<torrent>::get
|
|
|
|
, boost::bind(&piece_checker_data::torrent_ptr, _1))));
|
|
|
|
m_torrents.clear();
|
|
|
|
std::for_each(m_processing.begin(), m_processing.end()
|
|
|
|
, boost::bind(&torrent::abort
|
|
|
|
, boost::bind(&shared_ptr<torrent>::get
|
|
|
|
, boost::bind(&piece_checker_data::torrent_ptr, _1))));
|
|
|
|
m_processing.clear();
|
|
|
|
return;
|
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
if (!m_torrents.empty())
|
|
|
|
{
|
|
|
|
t = m_torrents.front();
|
|
|
|
if (t->abort)
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
// make sure the locking order is
|
|
|
|
// consistent to avoid dead locks
|
|
|
|
// we need to lock the session because closing
|
|
|
|
// torrents assume to have access to it
|
|
|
|
l.unlock();
|
|
|
|
session_impl::mutex_t::scoped_lock l2(m_ses.m_mutex);
|
|
|
|
l.lock();
|
|
|
|
|
|
|
|
t->torrent_ptr->abort();
|
2005-10-13 09:59:05 +02:00
|
|
|
m_torrents.pop_front();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
std::string error_msg;
|
|
|
|
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file(), error_msg);
|
|
|
|
|
|
|
|
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
|
|
|
t->torrent_ptr->get_handle()
|
|
|
|
, error_msg));
|
2006-04-25 23:04:48 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_ses.m_logger) << "fastresume data for "
|
|
|
|
<< t->torrent_ptr->torrent_file().name() << " rejected: "
|
|
|
|
<< error_msg << "\n";
|
|
|
|
#endif
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// clear the resume data now that it has been used
|
|
|
|
// (the fast resume data is now parsed and stored in t)
|
|
|
|
t->resume_data = entry();
|
|
|
|
bool up_to_date = t->torrent_ptr->check_fastresume(*t);
|
|
|
|
|
|
|
|
if (up_to_date)
|
|
|
|
{
|
|
|
|
// lock the session to add the new torrent
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
|
|
|
|
assert(m_torrents.front() == t);
|
|
|
|
|
|
|
|
t->torrent_ptr->files_checked(t->unfinished_pieces);
|
|
|
|
m_torrents.pop_front();
|
2006-05-28 21:03:54 +02:00
|
|
|
|
|
|
|
// we cannot add the torrent if the session is aborted.
|
|
|
|
if (!m_ses.m_abort)
|
2005-10-13 09:59:05 +02:00
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
|
|
|
|
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(torrent_finished_alert(
|
|
|
|
t->torrent_ptr->get_handle()
|
|
|
|
, "torrent is complete"));
|
|
|
|
}
|
2005-10-13 09:59:05 +02:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
peer_id id;
|
|
|
|
std::fill(id.begin(), id.end(), 0);
|
|
|
|
for (std::vector<tcp::endpoint>::const_iterator i = t->peers.begin();
|
|
|
|
i != t->peers.end(); ++i)
|
|
|
|
{
|
|
|
|
t->torrent_ptr->get_policy().peer_from_tracker(*i, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2005-10-13 09:59:05 +02:00
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
t->torrent_ptr->abort();
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
2006-05-28 21:03:54 +02:00
|
|
|
t.reset();
|
2005-10-13 09:59:05 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// lock the checker while we move the torrent from
|
|
|
|
// m_torrents to m_processing
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(m_torrents.front() == t);
|
|
|
|
|
|
|
|
m_torrents.pop_front();
|
|
|
|
m_processing.push_back(t);
|
|
|
|
if (!processing)
|
|
|
|
{
|
|
|
|
processing = t;
|
|
|
|
processing->processing = true;
|
2006-05-28 21:03:54 +02:00
|
|
|
t.reset();
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (const std::exception& e)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
// This will happen if the storage fails to initialize
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_mutex);
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
file_error_alert(
|
|
|
|
t->torrent_ptr->get_handle()
|
|
|
|
, e.what()));
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
2006-05-28 21:03:54 +02:00
|
|
|
t->torrent_ptr->abort();
|
2005-10-16 11:15:46 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(!m_torrents.empty());
|
|
|
|
m_torrents.pop_front();
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::cerr << "error while checking resume data\n";
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(!m_torrents.empty());
|
|
|
|
m_torrents.pop_front();
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!processing) continue;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
assert(processing);
|
|
|
|
|
|
|
|
float finished = false;
|
|
|
|
float progress = 0.f;
|
|
|
|
boost::tie(finished, progress) = processing->torrent_ptr->check_files();
|
2005-06-16 17:41:04 +02:00
|
|
|
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
processing->progress = progress;
|
|
|
|
if (processing->abort)
|
|
|
|
{
|
|
|
|
assert(!m_processing.empty());
|
|
|
|
assert(m_processing.front() == processing);
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
processing->torrent_ptr->abort();
|
2005-10-16 23:14:08 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
processing.reset();
|
|
|
|
m_processing.pop_front();
|
|
|
|
if (!m_processing.empty())
|
|
|
|
{
|
|
|
|
processing = m_processing.front();
|
|
|
|
processing->processing = true;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2005-10-13 09:59:05 +02:00
|
|
|
if (finished)
|
2005-05-25 12:01:01 +02:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
// lock the session to add the new torrent
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
|
|
|
|
assert(!m_processing.empty());
|
|
|
|
assert(m_processing.front() == processing);
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
// TODO: factor out the adding of torrents to the session
|
|
|
|
// and to the checker thread to avoid duplicating the
|
|
|
|
// check for abortion.
|
|
|
|
if (!m_ses.m_abort)
|
2005-10-13 09:59:05 +02:00
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
processing->torrent_ptr->files_checked(processing->unfinished_pieces);
|
|
|
|
m_ses.m_torrents.insert(std::make_pair(
|
|
|
|
processing->info_hash, processing->torrent_ptr));
|
|
|
|
if (processing->torrent_ptr->is_seed()
|
|
|
|
&& m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(torrent_finished_alert(
|
|
|
|
processing->torrent_ptr->get_handle()
|
|
|
|
, "torrent is complete"));
|
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
peer_id id;
|
|
|
|
std::fill(id.begin(), id.end(), 0);
|
|
|
|
for (std::vector<tcp::endpoint>::const_iterator i = processing->peers.begin();
|
2005-10-13 09:59:05 +02:00
|
|
|
i != processing->peers.end(); ++i)
|
2006-05-28 21:03:54 +02:00
|
|
|
{
|
|
|
|
processing->torrent_ptr->get_policy().peer_from_tracker(*i, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2005-10-13 09:59:05 +02:00
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
processing->torrent_ptr->abort();
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
|
|
|
processing.reset();
|
|
|
|
m_processing.pop_front();
|
|
|
|
if (!m_processing.empty())
|
|
|
|
{
|
|
|
|
processing = m_processing.front();
|
|
|
|
processing->processing = true;
|
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2006-05-28 21:03:54 +02:00
|
|
|
catch(std::exception const& e)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
|
|
|
// This will happen if the storage fails to initialize
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_mutex);
|
2005-10-16 11:15:46 +02:00
|
|
|
|
2004-03-03 14:47:12 +01:00
|
|
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
file_error_alert(
|
2005-10-13 09:59:05 +02:00
|
|
|
processing->torrent_ptr->get_handle()
|
2004-03-03 14:47:12 +01:00
|
|
|
, e.what()));
|
|
|
|
}
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(!m_processing.empty());
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
processing->torrent_ptr->abort();
|
2005-10-16 11:15:46 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
processing.reset();
|
|
|
|
m_processing.pop_front();
|
|
|
|
if (!m_processing.empty())
|
|
|
|
{
|
|
|
|
processing = m_processing.front();
|
|
|
|
processing->processing = true;
|
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
2003-10-31 05:02:51 +01:00
|
|
|
#ifndef NDEBUG
|
2004-02-26 13:59:01 +01:00
|
|
|
std::cerr << "error while checking files\n";
|
2003-10-31 05:02:51 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_mutex);
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(!m_processing.empty());
|
|
|
|
|
|
|
|
processing.reset();
|
|
|
|
m_processing.pop_front();
|
|
|
|
if (!m_processing.empty())
|
|
|
|
{
|
|
|
|
processing = m_processing.front();
|
|
|
|
processing->processing = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(false);
|
2003-10-31 05:02:51 +01:00
|
|
|
}
|
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2005-01-08 22:12:19 +01:00
|
|
|
detail::piece_checker_data* checker_impl::find_torrent(sha1_hash const& info_hash)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
2005-05-30 19:43:03 +02:00
|
|
|
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
2003-10-31 05:02:51 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
if ((*i)->info_hash == info_hash) return i->get();
|
|
|
|
}
|
|
|
|
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
|
|
= m_processing.begin(); i != m_processing.end(); ++i)
|
|
|
|
{
|
2006-05-15 00:30:05 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
if ((*i)->info_hash == info_hash) return i->get();
|
2003-10-31 05:02:51 +01:00
|
|
|
}
|
2005-10-13 09:59:05 +02:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2005-01-08 22:12:19 +01:00
|
|
|
void checker_impl::remove_torrent(sha1_hash const& info_hash)
|
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
2005-05-30 19:43:03 +02:00
|
|
|
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
2005-01-08 22:12:19 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
if ((*i)->info_hash == info_hash)
|
2005-01-08 22:12:19 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
assert((*i)->processing == false);
|
2005-01-08 22:12:19 +01:00
|
|
|
m_torrents.erase(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2006-05-15 00:30:05 +02:00
|
|
|
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
|
|
= m_processing.begin(); i != m_processing.end(); ++i)
|
|
|
|
{
|
|
|
|
if ((*i)->info_hash == info_hash)
|
|
|
|
{
|
|
|
|
assert((*i)->processing == false);
|
|
|
|
m_torrents.erase(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(false);
|
2005-01-08 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
session_impl::session_impl(
|
|
|
|
std::pair<int, int> listen_port_range
|
|
|
|
, const fingerprint& cl_fprint
|
2006-05-20 17:30:40 +02:00
|
|
|
, char const* listen_interface)
|
2006-05-21 01:24:19 +02:00
|
|
|
: m_tracker_manager(m_settings)
|
2004-02-26 13:59:01 +01:00
|
|
|
, m_listen_port_range(listen_port_range)
|
2006-05-20 17:30:40 +02:00
|
|
|
, m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
|
2004-02-26 13:59:01 +01:00
|
|
|
, m_abort(false)
|
|
|
|
, m_upload_rate(-1)
|
2004-03-28 19:45:37 +02:00
|
|
|
, m_download_rate(-1)
|
2004-10-29 15:21:09 +02:00
|
|
|
, m_max_uploads(-1)
|
|
|
|
, m_max_connections(-1)
|
2005-11-02 17:28:39 +01:00
|
|
|
, m_half_open_limit(-1)
|
2004-02-26 13:59:01 +01:00
|
|
|
, m_incoming_connection(false)
|
2006-05-20 17:30:40 +02:00
|
|
|
, m_last_tick(microsec_clock::universal_time())
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_timer(m_selector)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2005-07-06 02:58:23 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2005-09-01 23:04:21 +02:00
|
|
|
m_logger = create_log("main_session", false);
|
2005-10-16 18:58:41 +02:00
|
|
|
using boost::posix_time::second_clock;
|
|
|
|
using boost::posix_time::to_simple_string;
|
|
|
|
(*m_logger) << to_simple_string(second_clock::universal_time()) << "\n";
|
2004-03-29 08:10:23 +02:00
|
|
|
#endif
|
2004-11-01 00:16:08 +01:00
|
|
|
std::fill(m_extension_enabled, m_extension_enabled
|
2006-04-25 23:04:48 +02:00
|
|
|
+ num_supported_extensions, true);
|
2004-02-26 13:59:01 +01:00
|
|
|
// ---- generate a peer id ----
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
std::srand((unsigned int)std::time(0));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
m_key = rand() + (rand() << 15) + (rand() << 30);
|
2004-02-26 13:59:01 +01:00
|
|
|
std::string print = cl_fprint.to_string();
|
2004-07-18 02:39:58 +02:00
|
|
|
assert(print.length() <= 20);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
// the client's fingerprint
|
|
|
|
std::copy(
|
|
|
|
print.begin()
|
|
|
|
, print.begin() + print.length()
|
|
|
|
, m_peer_id.begin());
|
2003-10-26 18:35:23 +01:00
|
|
|
|
2004-03-24 23:50:07 +01:00
|
|
|
// http-accepted characters:
|
2005-11-08 01:55:33 +01:00
|
|
|
static char const printable[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz-_.!~*'()";
|
2004-03-24 23:50:07 +01:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
// the random number
|
|
|
|
for (unsigned char* i = m_peer_id.begin() + print.length();
|
2005-09-01 23:04:21 +02:00
|
|
|
i != m_peer_id.end(); ++i)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2004-03-24 23:50:07 +01:00
|
|
|
*i = printable[rand() % (sizeof(printable)-1)];
|
2003-10-25 03:31:06 +02:00
|
|
|
}
|
2005-09-18 12:18:23 +02:00
|
|
|
// this says that we support the extensions
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
m_timer.expires_from_now(seconds(1));
|
|
|
|
m_timer.async_wait(bind(&session_impl::second_tick, this, _1));
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-11-01 00:16:08 +01:00
|
|
|
bool session_impl::extensions_enabled() const
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
const int n = num_supported_extensions;
|
2004-11-01 00:16:08 +01:00
|
|
|
return std::find(m_extension_enabled
|
|
|
|
, m_extension_enabled + n, true) != m_extension_enabled + n;
|
|
|
|
}
|
|
|
|
|
2006-05-21 01:24:19 +02:00
|
|
|
void session_impl::set_settings(session_settings const& s)
|
|
|
|
{
|
|
|
|
if (m_settings.sequenced_download_threshold
|
|
|
|
!= s.sequenced_download_threshold)
|
|
|
|
{
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
|
|
|
if (t.valid_metadata())
|
|
|
|
t.picker().set_sequenced_download_threshold(
|
|
|
|
s.sequenced_download_threshold);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_settings = s;
|
|
|
|
}
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
void session_impl::open_listen_port()
|
|
|
|
{
|
|
|
|
try
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
// create listener socket
|
2006-04-25 23:04:48 +02:00
|
|
|
m_listen_socket = boost::shared_ptr<socket_acceptor>(new socket_acceptor(m_selector));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2006-05-20 17:30:40 +02:00
|
|
|
m_listen_socket->open(asio::ip::tcp::v4());
|
2006-04-25 23:04:48 +02:00
|
|
|
m_listen_socket->bind(m_listen_interface);
|
|
|
|
m_listen_socket->listen();
|
2004-02-26 13:59:01 +01:00
|
|
|
break;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (asio::error& e)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
// TODO: make sure this is correct
|
|
|
|
if (e.code() == asio::error::host_not_found)
|
2004-02-26 01:27:06 +01:00
|
|
|
{
|
2004-03-30 21:11:07 +02:00
|
|
|
if (m_alerts.should_post(alert::fatal))
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
std::string msg = "cannot listen on the given interface '"
|
|
|
|
+ m_listen_interface.address().to_string() + "'";
|
2004-03-30 21:11:07 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert(msg));
|
|
|
|
}
|
2005-07-06 02:58:23 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2006-04-25 23:04:48 +02:00
|
|
|
std::string msg = "cannot listen on the given interface '"
|
|
|
|
+ m_listen_interface.address().to_string() + "'";
|
2004-02-26 13:59:01 +01:00
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#endif
|
2004-03-30 21:11:07 +02:00
|
|
|
assert(m_listen_socket.unique());
|
2004-02-26 13:59:01 +01:00
|
|
|
m_listen_socket.reset();
|
|
|
|
break;
|
2004-02-26 01:27:06 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
m_listen_interface.port(m_listen_interface.port() + 1);
|
|
|
|
if (m_listen_interface.port() > m_listen_port_range.second)
|
2004-01-26 11:29:00 +01:00
|
|
|
{
|
2004-02-26 13:59:01 +01:00
|
|
|
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()));
|
2005-07-06 02:58:23 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2004-02-26 13:59:01 +01:00
|
|
|
(*m_logger) << msg.str() << "\n";
|
|
|
|
#endif
|
|
|
|
m_listen_socket.reset();
|
|
|
|
break;
|
2004-01-26 11:29:00 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (asio::error& e)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_alerts.should_post(alert::fatal))
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(listen_failed_alert(
|
|
|
|
std::string("failed to open listen port") + e.what()));
|
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-07-06 02:58:23 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2004-02-26 13:59:01 +01:00
|
|
|
if (m_listen_socket)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
(*m_logger) << "listening on port: " << m_listen_interface.port() << "\n";
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-25 03:31:06 +02:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_listen_socket) async_accept();
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-11-02 17:28:39 +01:00
|
|
|
void session_impl::process_connection_queue()
|
|
|
|
{
|
|
|
|
while (!m_connection_queue.empty())
|
|
|
|
{
|
|
|
|
if ((int)m_half_open.size() >= m_half_open_limit
|
|
|
|
&& m_half_open_limit > 0)
|
|
|
|
return;
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
connection_queue::value_type c = m_connection_queue.front();
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
m_connection_queue.pop_front();
|
|
|
|
assert(c->associated_torrent().lock().get());
|
|
|
|
c->connect();
|
|
|
|
m_half_open.insert(std::make_pair(c->get_socket(), c));
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
2006-06-25 00:30:59 +02:00
|
|
|
c->disconnect();
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << "connect failed [" << c->remote() << "]: "
|
|
|
|
<< e.what() << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
2005-11-02 17:28:39 +01:00
|
|
|
}
|
|
|
|
}
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session_impl::async_accept()
|
|
|
|
{
|
|
|
|
shared_ptr<stream_socket> c(new stream_socket(m_selector));
|
|
|
|
m_listen_socket->async_accept(*c
|
|
|
|
, bind(&session_impl::on_incoming_connection, this, c
|
|
|
|
, weak_ptr<socket_acceptor>(m_listen_socket), _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_incoming_connection(shared_ptr<stream_socket> const& s
|
|
|
|
, weak_ptr<socket_acceptor> const& listen_socket, asio::error const& e) try
|
|
|
|
{
|
|
|
|
if (listen_socket.expired())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e == asio::error::operation_aborted)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
assert(listen_socket.lock() == m_listen_socket);
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
async_accept();
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
std::string msg = "error accepting connection on '"
|
|
|
|
+ m_listen_interface.address().to_string() + "'";
|
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#endif
|
|
|
|
assert(m_listen_socket.unique());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we got a connection request!
|
|
|
|
m_incoming_connection = true;
|
|
|
|
tcp::endpoint endp = s->remote_endpoint();
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << endp << " <== INCOMING CONNECTION\n";
|
|
|
|
#endif
|
2006-05-20 17:30:40 +02:00
|
|
|
if (m_ip_filter.access(endp.address().to_v4()) & ip_filter::blocked)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << "filtered blocked ip\n";
|
|
|
|
#endif
|
|
|
|
// TODO: issue an info-alert when an ip is blocked!!
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::intrusive_ptr<peer_connection> c(
|
|
|
|
new bt_peer_connection(*this, s));
|
|
|
|
#ifndef NDEBUG
|
|
|
|
c->m_in_constructor = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_connections.insert(std::make_pair(s, c));
|
|
|
|
}
|
|
|
|
catch (std::exception& exc)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::string err = exc.what();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::connection_failed(boost::shared_ptr<stream_socket> const& s
|
|
|
|
, tcp::endpoint const& a, char const* message)
|
|
|
|
#ifndef NDEBUG
|
|
|
|
try
|
|
|
|
#endif
|
2006-01-06 21:20:20 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
|
2006-01-06 21:20:20 +01:00
|
|
|
connection_map::iterator p = m_connections.find(s);
|
|
|
|
|
|
|
|
// the connection may have been disconnected in the receive or send phase
|
|
|
|
if (p != m_connections.end())
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post(alert::debug))
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(
|
|
|
|
peer_error_alert(
|
|
|
|
a
|
2006-04-25 23:04:48 +02:00
|
|
|
, p->second->pid()
|
2006-01-06 21:20:20 +01:00
|
|
|
, message));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
2006-04-25 23:04:48 +02:00
|
|
|
(*p->second->m_logger) << "*** CONNECTION FAILED " << message << "\n";
|
2006-01-06 21:20:20 +01:00
|
|
|
#endif
|
|
|
|
p->second->set_failed();
|
2006-04-25 23:04:48 +02:00
|
|
|
p->second->disconnect();
|
2006-01-06 21:20:20 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// the error was not in one of the connected
|
|
|
|
// conenctions. Look among the half-open ones.
|
|
|
|
p = m_half_open.find(s);
|
|
|
|
if (p != m_half_open.end())
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post(alert::debug))
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(
|
|
|
|
peer_error_alert(
|
|
|
|
a
|
2006-04-25 23:04:48 +02:00
|
|
|
, p->second->pid()
|
2006-01-06 21:20:20 +01:00
|
|
|
, message));
|
|
|
|
}
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2006-04-25 23:04:48 +02:00
|
|
|
(*m_logger) << "CLOSED: " << a.address().to_string()
|
|
|
|
<< " " << message << "\n";
|
2006-01-06 21:20:20 +01:00
|
|
|
#endif
|
|
|
|
p->second->set_failed();
|
2006-04-25 23:04:48 +02:00
|
|
|
p->second->disconnect();
|
2006-01-06 21:20:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-09 19:17:09 +01:00
|
|
|
#ifndef NDEBUG
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
2003-11-09 19:17:09 +01:00
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session_impl::close_connection(boost::intrusive_ptr<peer_connection> const& p)
|
|
|
|
{
|
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2003-12-01 06:01:40 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
assert(p->is_disconnecting());
|
2004-09-08 01:16:11 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (p->is_connecting())
|
|
|
|
{
|
|
|
|
assert(p->is_local());
|
2006-05-28 21:03:54 +02:00
|
|
|
assert(m_connections.find(p->get_socket()) == m_connections.end());
|
2006-04-25 23:04:48 +02:00
|
|
|
// Since this peer is still connecting, will not be
|
|
|
|
// in the list of completed connections.
|
|
|
|
connection_map::iterator i = m_half_open.find(p->get_socket());
|
|
|
|
if (i == m_half_open.end())
|
2004-09-08 01:16:11 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
// this connection is not in the half-open list, so it
|
|
|
|
// has to be in the queue, waiting to be connected.
|
|
|
|
connection_queue::iterator j = std::find(
|
|
|
|
m_connection_queue.begin(), m_connection_queue.end(), p);
|
2006-06-25 00:30:59 +02:00
|
|
|
|
|
|
|
// if this connection was closed while being connected
|
|
|
|
// it has been removed from the connection queue and
|
|
|
|
// not yet put into the half-open queue.
|
2006-04-25 23:04:48 +02:00
|
|
|
if (j != m_connection_queue.end())
|
|
|
|
m_connection_queue.erase(j);
|
2004-09-08 01:16:11 +02:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
else
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
m_half_open.erase(i);
|
|
|
|
process_connection_queue();
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
assert(m_half_open.find(p->get_socket()) == m_half_open.end());
|
|
|
|
assert(std::find(m_connection_queue.begin()
|
|
|
|
, m_connection_queue.end(), p) == m_connection_queue.end());
|
2006-04-25 23:04:48 +02:00
|
|
|
connection_map::iterator i = m_connections.find(p->get_socket());
|
2006-05-28 21:03:54 +02:00
|
|
|
// assert (i != m_connections.end());
|
2006-04-25 23:04:48 +02:00
|
|
|
if (i != m_connections.end())
|
|
|
|
m_connections.erase(i);
|
|
|
|
}
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session_impl::second_tick(asio::error const& e) try
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_mutex);
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << "*** SECOND TIMER FAILED " << e.what() << "\n";
|
2004-01-15 21:03:23 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
m_abort = true;
|
|
|
|
m_selector.interrupt();
|
|
|
|
return;
|
|
|
|
}
|
2006-05-28 21:03:54 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_abort) return;
|
2006-05-20 17:30:40 +02:00
|
|
|
float tick_interval = (microsec_clock::universal_time()
|
2006-04-25 23:04:48 +02:00
|
|
|
- m_last_tick).total_milliseconds() / 1000.f;
|
2006-05-20 17:30:40 +02:00
|
|
|
m_last_tick = microsec_clock::universal_time();
|
2004-01-15 21:03:23 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_timer.expires_from_now(seconds(1));
|
|
|
|
m_timer.async_wait(bind(&session_impl::second_tick, this, _1));
|
|
|
|
|
|
|
|
// do the second_tick() on each connection
|
|
|
|
// this will update their statistics (download and upload speeds)
|
|
|
|
// also purge sockets that have timed out
|
|
|
|
// and keep sockets open by keeping them alive.
|
|
|
|
for (connection_map::iterator i = m_connections.begin();
|
|
|
|
i != m_connections.end();)
|
|
|
|
{
|
|
|
|
// we need to do like this because j->second->disconnect() will
|
|
|
|
// erase the connection from the map we're iterating
|
|
|
|
connection_map::iterator j = i;
|
|
|
|
++i;
|
|
|
|
// if this socket has timed out
|
|
|
|
// close it.
|
2006-05-28 21:03:54 +02:00
|
|
|
peer_connection& c = *j->second;
|
|
|
|
if (c.has_timed_out())
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_alerts.should_post(alert::debug))
|
2004-01-15 21:03:23 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
m_alerts.post_alert(
|
|
|
|
peer_error_alert(
|
2006-05-28 21:03:54 +02:00
|
|
|
c.remote()
|
|
|
|
, c.pid()
|
2006-04-25 23:04:48 +02:00
|
|
|
, "connection timed out"));
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
2006-05-28 21:03:54 +02:00
|
|
|
(*c.m_logger) << "*** CONNECTION TIMED OUT\n";
|
2005-09-01 23:04:21 +02:00
|
|
|
#endif
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
c.set_failed();
|
|
|
|
c.disconnect();
|
2006-04-25 23:04:48 +02:00
|
|
|
continue;
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2004-01-15 21:03:23 +01:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
c.keep_alive();
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// check each torrent for tracker updates
|
|
|
|
// TODO: do this in a timer-event in each torrent instead
|
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
|
|
|
= m_torrents.begin(); i != m_torrents.end();)
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
|
|
|
assert(!t.is_aborted());
|
|
|
|
if (t.should_request())
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
tracker_request req = t.generate_tracker_request();
|
|
|
|
req.listen_port = m_listen_interface.port();
|
|
|
|
req.key = m_key;
|
|
|
|
m_tracker_manager.queue_request(m_selector, req, t.tracker_login()
|
|
|
|
, i->second);
|
2004-02-24 20:23:37 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_alerts.should_post(alert::info))
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
m_alerts.post_alert(
|
|
|
|
tracker_announce_alert(
|
|
|
|
t.get_handle(), "tracker announce"));
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// tick() will set the used upload quota
|
|
|
|
t.second_tick(m_stat, tick_interval);
|
|
|
|
++i;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// don't pass in the tick_interval here, because
|
|
|
|
// the stats have already been adjusted in
|
|
|
|
// the peer's second tick.
|
2006-07-26 12:21:25 +02:00
|
|
|
m_stat.second_tick(tick_interval);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// distribute the maximum upload rate among the torrents
|
|
|
|
|
2006-05-02 01:34:37 +02:00
|
|
|
assert(m_upload_rate >= -1);
|
|
|
|
assert(m_download_rate >= -1);
|
|
|
|
assert(m_max_uploads >= -1);
|
|
|
|
assert(m_max_connections >= -1);
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
allocate_resources(m_upload_rate == -1
|
|
|
|
? std::numeric_limits<int>::max()
|
|
|
|
: int(m_upload_rate * tick_interval)
|
|
|
|
, m_torrents
|
|
|
|
, &torrent::m_ul_bandwidth_quota);
|
|
|
|
|
|
|
|
allocate_resources(m_download_rate == -1
|
|
|
|
? std::numeric_limits<int>::max()
|
|
|
|
: int(m_download_rate * tick_interval)
|
|
|
|
, m_torrents
|
|
|
|
, &torrent::m_dl_bandwidth_quota);
|
|
|
|
|
|
|
|
allocate_resources(m_max_uploads == -1
|
|
|
|
? std::numeric_limits<int>::max()
|
|
|
|
: m_max_uploads
|
|
|
|
, m_torrents
|
|
|
|
, &torrent::m_uploads_quota);
|
|
|
|
|
|
|
|
allocate_resources(m_max_connections == -1
|
|
|
|
? std::numeric_limits<int>::max()
|
|
|
|
: m_max_connections
|
|
|
|
, m_torrents
|
|
|
|
, &torrent::m_connections_quota);
|
|
|
|
|
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
|
|
|
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
|
|
|
{
|
2006-05-15 23:19:19 +02:00
|
|
|
#ifndef NDEBUG
|
2006-05-15 00:30:05 +02:00
|
|
|
i->second->check_invariant();
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
i->second->distribute_resources();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception& exc)
|
|
|
|
{
|
2003-11-02 22:06:50 +01:00
|
|
|
#ifndef NDEBUG
|
2006-04-25 23:04:48 +02:00
|
|
|
std::string err = exc.what();
|
2003-11-02 22:06:50 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
}; // msvc 7.1 seems to require this
|
2003-11-02 22:06:50 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session_impl::connection_completed(
|
|
|
|
boost::intrusive_ptr<peer_connection> const& p)
|
|
|
|
#ifndef NDEBUG
|
|
|
|
try
|
2005-09-01 23:04:21 +02:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
|
|
|
|
if (m_abort) return;
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
connection_map::iterator i = m_half_open.find(p->get_socket());
|
2005-06-06 12:33:44 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_connections.insert(std::make_pair(p->get_socket(), p));
|
|
|
|
if (i != m_half_open.end()) m_half_open.erase(i);
|
|
|
|
process_connection_queue();
|
|
|
|
}
|
2003-11-10 14:15:41 +01:00
|
|
|
#ifndef NDEBUG
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
2003-11-10 14:15:41 +01:00
|
|
|
#endif
|
2004-04-18 14:28:02 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session_impl::operator()()
|
|
|
|
{
|
|
|
|
eh_initializer();
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
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();
|
|
|
|
}
|
2004-10-29 15:21:09 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::posix_time::ptime timer = second_clock::universal_time();
|
2004-10-29 15:21:09 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// for(;;)
|
|
|
|
// {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
m_selector.run();
|
|
|
|
assert(m_abort == true);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2006-05-28 21:03:54 +02:00
|
|
|
std::cerr << e.what() << "\n";
|
2006-04-25 23:04:48 +02:00
|
|
|
std::string err = e.what();
|
|
|
|
#endif
|
|
|
|
assert(false);
|
|
|
|
}
|
2003-11-10 14:15:41 +01:00
|
|
|
|
2006-07-13 00:55:06 +02:00
|
|
|
deadline_timer tracker_timer(m_selector);
|
2005-05-12 01:03:12 +02:00
|
|
|
|
2006-07-13 00:55:06 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_mutex);
|
|
|
|
|
|
|
|
m_tracker_manager.abort_all_requests();
|
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i =
|
|
|
|
m_torrents.begin(); i != m_torrents.end(); ++i)
|
|
|
|
{
|
|
|
|
i->second->abort();
|
|
|
|
if (!i->second->is_paused() || i->second->should_request())
|
2005-05-12 01:03:12 +02:00
|
|
|
{
|
2006-07-13 00:55:06 +02:00
|
|
|
tracker_request req = i->second->generate_tracker_request();
|
|
|
|
req.listen_port = m_listen_interface.port();
|
|
|
|
req.key = m_key;
|
|
|
|
std::string login = i->second->tracker_login();
|
|
|
|
m_tracker_manager.queue_request(m_selector, req, login);
|
2005-05-12 01:03:12 +02:00
|
|
|
}
|
2003-10-30 00:28:09 +01:00
|
|
|
}
|
2006-07-13 00:55:06 +02:00
|
|
|
tracker_timer.expires_from_now(boost::posix_time::seconds(
|
|
|
|
m_settings.stop_tracker_timeout));
|
|
|
|
tracker_timer.async_wait(bind(&demuxer::interrupt, &m_selector));
|
|
|
|
l.unlock();
|
2003-10-27 16:43:33 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_selector.reset();
|
|
|
|
m_selector.run();
|
|
|
|
|
2006-07-13 00:55:06 +02:00
|
|
|
l.lock();
|
2006-05-28 21:03:54 +02:00
|
|
|
assert(m_abort);
|
|
|
|
m_abort = true;
|
|
|
|
|
2006-07-18 18:29:35 +02:00
|
|
|
while (!m_connections.empty())
|
|
|
|
m_connections.begin()->second->disconnect();
|
2006-07-16 02:08:50 +02:00
|
|
|
|
2006-07-18 18:29:35 +02:00
|
|
|
while (!m_half_open.empty())
|
|
|
|
m_half_open.begin()->second->disconnect();
|
2006-07-16 02:08:50 +02:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
m_connection_queue.clear();
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin();
|
|
|
|
i != m_torrents.end(); ++i)
|
|
|
|
{
|
|
|
|
assert(i->second->num_peers() == 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_torrents.clear();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2005-11-09 13:40:07 +01:00
|
|
|
assert(m_torrents.empty());
|
|
|
|
assert(m_connections.empty());
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the return value from this function is valid only as long as the
|
|
|
|
// session is locked!
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::weak_ptr<torrent> session_impl::find_torrent(sha1_hash const& info_hash)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
|
|
|
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
|
|
|
= m_torrents.find(info_hash);
|
2004-03-03 14:47:12 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j
|
2005-06-13 12:58:00 +02:00
|
|
|
= m_torrents.begin(); j != m_torrents.end(); ++j)
|
2004-03-03 14:47:12 +01:00
|
|
|
{
|
|
|
|
torrent* p = boost::get_pointer(j->second);
|
2004-04-17 14:29:35 +02:00
|
|
|
assert(p);
|
2004-03-03 14:47:12 +01:00
|
|
|
}
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
if (i != m_torrents.end()) return i->second;
|
|
|
|
return boost::weak_ptr<torrent>();
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
|
|
|
|
2005-07-06 02:58:23 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2005-09-01 23:04:21 +02:00
|
|
|
boost::shared_ptr<logger> session_impl::create_log(std::string const& name, bool append)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2004-11-30 12:17:32 +01:00
|
|
|
// current options are file_logger, cout_logger and null_logger
|
2006-05-15 00:30:05 +02:00
|
|
|
return boost::shared_ptr<logger>(new logger(name + ".log", append));
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-11-09 19:17:09 +01:00
|
|
|
#endif
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
#ifndef NDEBUG
|
2004-02-26 13:59:01 +01:00
|
|
|
void session_impl::check_invariant(const char *place)
|
|
|
|
{
|
|
|
|
assert(place);
|
2004-01-25 05:18:08 +01:00
|
|
|
|
2005-11-02 17:28:39 +01:00
|
|
|
for (connection_map::iterator i = m_half_open.begin();
|
|
|
|
i != m_half_open.end(); ++i)
|
|
|
|
{
|
|
|
|
assert(i->second->is_connecting());
|
|
|
|
}
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
for (connection_map::iterator i = m_connections.begin();
|
2005-06-13 12:58:00 +02:00
|
|
|
i != m_connections.end(); ++i)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2005-10-17 15:45:53 +02:00
|
|
|
assert(i->second);
|
2005-11-07 03:18:39 +01:00
|
|
|
assert(!i->second->is_connecting());
|
2006-07-27 20:07:51 +02:00
|
|
|
if (i->second->is_connecting())
|
2003-12-01 06:01:40 +01:00
|
|
|
{
|
2004-02-26 13:59:01 +01:00
|
|
|
std::ofstream error_log("error.log", std::ios_base::app);
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::intrusive_ptr<peer_connection> p = i->second;
|
2005-11-02 17:28:39 +01:00
|
|
|
error_log << "peer_connection::is_connecting() " << p->is_connecting() << "\n";
|
2004-03-28 19:45:37 +02:00
|
|
|
error_log << "peer_connection::can_write() " << p->can_write() << "\n";
|
|
|
|
error_log << "peer_connection::can_read() " << p->can_read() << "\n";
|
|
|
|
error_log << "peer_connection::ul_quota_left " << p->m_ul_bandwidth_quota.left() << "\n";
|
|
|
|
error_log << "peer_connection::dl_quota_left " << p->m_dl_bandwidth_quota.left() << "\n";
|
|
|
|
error_log << "peer_connection::m_ul_bandwidth_quota.given " << p->m_ul_bandwidth_quota.given << "\n";
|
2006-04-25 23:04:48 +02:00
|
|
|
error_log << "peer_connection::get_peer_id " << p->pid() << "\n";
|
2004-02-26 13:59:01 +01:00
|
|
|
error_log << "place: " << place << "\n";
|
|
|
|
error_log.flush();
|
|
|
|
assert(false);
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = i->second->associated_torrent().lock();
|
|
|
|
|
|
|
|
if (t)
|
2004-02-26 13:59:01 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
assert(t->get_policy().has_connection(boost::get_pointer(i->second)));
|
2003-12-01 06:01:40 +01:00
|
|
|
}
|
|
|
|
}
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
2003-12-01 06:01:40 +01:00
|
|
|
#endif
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
}}
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-02-26 01:27:06 +01:00
|
|
|
session::session(
|
2004-03-29 00:44:40 +02:00
|
|
|
fingerprint const& id
|
|
|
|
, std::pair<int, int> listen_port_range
|
|
|
|
, char const* listen_interface)
|
2004-02-26 01:27:06 +01:00
|
|
|
: m_impl(listen_port_range, id, listen_interface)
|
2004-01-25 13:37:15 +01:00
|
|
|
, m_checker_impl(m_impl)
|
2003-11-07 02:44:30 +01:00
|
|
|
, m_thread(boost::ref(m_impl))
|
|
|
|
, m_checker_thread(boost::ref(m_checker_impl))
|
|
|
|
{
|
2005-11-18 02:12:21 +01:00
|
|
|
// turn off the filename checking in boost.filesystem
|
|
|
|
using namespace boost::filesystem;
|
2006-04-25 23:04:48 +02:00
|
|
|
if (path::default_name_check_writable())
|
|
|
|
path::default_name_check(no_check);
|
2004-01-26 11:29:00 +01:00
|
|
|
assert(listen_port_range.first > 0);
|
|
|
|
assert(listen_port_range.first < listen_port_range.second);
|
2003-11-07 02:44:30 +01:00
|
|
|
#ifndef NDEBUG
|
2003-12-16 14:33:29 +01:00
|
|
|
// this test was added after it came to my attention
|
|
|
|
// that devstudios managed c++ failed to generate
|
|
|
|
// correct code for boost.function
|
2003-11-07 02:44:30 +01:00
|
|
|
boost::function0<void> test = boost::ref(m_impl);
|
|
|
|
assert(!test.empty());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-03-29 00:44:40 +02:00
|
|
|
session::session(fingerprint const& id)
|
|
|
|
: m_impl(std::make_pair(0, 0), id)
|
2004-01-25 13:37:15 +01:00
|
|
|
, m_checker_impl(m_impl)
|
2003-12-16 14:33:29 +01:00
|
|
|
, m_thread(boost::ref(m_impl))
|
|
|
|
, m_checker_thread(boost::ref(m_checker_impl))
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
boost::function0<void> test = boost::ref(m_impl);
|
|
|
|
assert(!test.empty());
|
|
|
|
#endif
|
|
|
|
}
|
2003-11-07 02:44:30 +01:00
|
|
|
|
2004-11-01 00:16:08 +01:00
|
|
|
void session::disable_extensions()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-11-01 00:16:08 +01:00
|
|
|
std::fill(m_impl.m_extension_enabled, m_impl.m_extension_enabled
|
2006-04-25 23:04:48 +02:00
|
|
|
+ num_supported_extensions, false);
|
2004-11-01 00:16:08 +01:00
|
|
|
}
|
|
|
|
|
2005-07-06 02:58:23 +02:00
|
|
|
void session::set_ip_filter(ip_filter const& f)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2005-07-06 02:58:23 +02:00
|
|
|
m_impl.m_ip_filter = f;
|
2005-07-16 02:56:50 +02:00
|
|
|
|
|
|
|
// Close connections whose endpoint is filtered
|
|
|
|
// by the new ip-filter
|
|
|
|
for (detail::session_impl::connection_map::iterator i
|
|
|
|
= m_impl.m_connections.begin(); i != m_impl.m_connections.end();)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
tcp::endpoint sender = i->first->remote_endpoint();
|
2006-05-20 17:30:40 +02:00
|
|
|
if (m_impl.m_ip_filter.access(sender.address().to_v4())
|
2005-07-16 02:56:50 +02:00
|
|
|
& ip_filter::blocked)
|
|
|
|
{
|
2005-09-01 23:04:21 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
|
|
|
(*i->second->m_logger) << "*** CONNECTION FILTERED'\n";
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
detail::session_impl::connection_map::iterator j = i;
|
|
|
|
++i;
|
|
|
|
j->second->disconnect();
|
2005-07-16 02:56:50 +02:00
|
|
|
}
|
|
|
|
else ++i;
|
|
|
|
}
|
2005-07-06 02:58:23 +02:00
|
|
|
}
|
|
|
|
|
2004-12-21 13:30:09 +01:00
|
|
|
void session::set_peer_id(peer_id const& id)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-12-21 13:30:09 +01:00
|
|
|
m_impl.m_peer_id = id;
|
|
|
|
}
|
|
|
|
|
2005-01-08 22:12:19 +01:00
|
|
|
void session::set_key(int key)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2005-01-08 22:12:19 +01:00
|
|
|
m_impl.m_key = key;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void session::enable_extension(extension_index i)
|
2004-11-01 00:16:08 +01:00
|
|
|
{
|
|
|
|
assert(i >= 0);
|
2006-04-25 23:04:48 +02:00
|
|
|
assert(i < num_supported_extensions);
|
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-11-01 00:16:08 +01:00
|
|
|
m_impl.m_extension_enabled[i] = true;
|
2005-09-18 12:18:23 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// // this says that we support the extensions
|
|
|
|
// std::memcpy(&m_impl.m_peer_id[17], "ext", 3);
|
2004-11-01 00:16:08 +01:00
|
|
|
}
|
|
|
|
|
2004-11-18 23:33:50 +01:00
|
|
|
std::vector<torrent_handle> session::get_torrents()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_checker_impl.m_mutex);
|
2004-11-18 23:33:50 +01:00
|
|
|
std::vector<torrent_handle> ret;
|
2005-10-13 09:59:05 +02:00
|
|
|
for (std::deque<boost::shared_ptr<detail::piece_checker_data> >::iterator i
|
2004-12-21 13:30:09 +01:00
|
|
|
= m_checker_impl.m_torrents.begin()
|
|
|
|
, end(m_checker_impl.m_torrents.end()); i != end; ++i)
|
2004-11-18 23:33:50 +01:00
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
if ((*i)->abort) continue;
|
2004-12-21 13:30:09 +01:00
|
|
|
ret.push_back(torrent_handle(&m_impl, &m_checker_impl
|
2005-10-13 09:59:05 +02:00
|
|
|
, (*i)->info_hash));
|
2004-11-18 23:33:50 +01:00
|
|
|
}
|
|
|
|
|
2004-12-21 13:30:09 +01:00
|
|
|
for (detail::session_impl::torrent_map::iterator i
|
|
|
|
= m_impl.m_torrents.begin(), end(m_impl.m_torrents.end());
|
|
|
|
i != end; ++i)
|
2004-11-18 23:33:50 +01:00
|
|
|
{
|
2004-12-21 13:30:09 +01:00
|
|
|
if (i->second->is_aborted()) continue;
|
|
|
|
ret.push_back(torrent_handle(&m_impl, &m_checker_impl
|
|
|
|
, i->first));
|
2004-11-18 23:33:50 +01:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-11-02 22:06:50 +01:00
|
|
|
// if the torrent already exists, this will throw duplicate_torrent
|
2004-01-07 01:48:02 +01:00
|
|
|
torrent_handle session::add_torrent(
|
2005-10-16 18:58:41 +02:00
|
|
|
torrent_info const& ti
|
2004-06-14 01:30:42 +02:00
|
|
|
, boost::filesystem::path const& save_path
|
2005-05-13 02:39:39 +02:00
|
|
|
, entry const& resume_data
|
2005-07-10 12:42:00 +02:00
|
|
|
, bool compact_mode
|
|
|
|
, int block_size)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
// make sure the block_size is an even power of 2
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (int i = 0; i < 32; ++i)
|
|
|
|
{
|
|
|
|
if (block_size & (1 << i))
|
|
|
|
{
|
|
|
|
assert((block_size & ~(1 << i)) == 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-10-18 12:46:55 +02:00
|
|
|
assert(!save_path.empty());
|
2004-06-14 01:30:42 +02:00
|
|
|
|
2004-03-30 01:25:13 +02:00
|
|
|
if (ti.begin_files() == ti.end_files())
|
|
|
|
throw std::runtime_error("no files in torrent");
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-10-16 01:16:39 +02:00
|
|
|
// lock the session and the checker thread (the order is important!)
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
|
|
|
mutex::scoped_lock l2(m_checker_impl.m_mutex);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-11-09 13:40:07 +01:00
|
|
|
if (m_impl.m_abort)
|
|
|
|
throw std::runtime_error("session is closing");
|
|
|
|
|
2005-10-16 01:16:39 +02:00
|
|
|
// is the torrent already active?
|
2006-04-25 23:04:48 +02:00
|
|
|
if (!m_impl.find_torrent(ti.info_hash()).expired())
|
2005-10-16 01:16:39 +02:00
|
|
|
throw duplicate_torrent();
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2004-08-30 11:08:36 +02:00
|
|
|
// is the torrent currently being checked?
|
|
|
|
if (m_checker_impl.find_torrent(ti.info_hash()))
|
|
|
|
throw duplicate_torrent();
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
// create the torrent and the data associated with
|
|
|
|
// the checker thread and store it before starting
|
|
|
|
// the thread
|
2004-01-02 21:46:24 +01:00
|
|
|
boost::shared_ptr<torrent> torrent_ptr(
|
2005-10-16 18:58:41 +02:00
|
|
|
new torrent(m_impl, m_checker_impl, ti, save_path
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_impl.m_listen_interface, compact_mode, block_size
|
|
|
|
, m_impl.m_settings));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
boost::shared_ptr<detail::piece_checker_data> d(
|
|
|
|
new detail::piece_checker_data);
|
|
|
|
d->torrent_ptr = torrent_ptr;
|
|
|
|
d->save_path = save_path;
|
|
|
|
d->info_hash = ti.info_hash();
|
|
|
|
d->resume_data = resume_data;
|
2004-11-21 11:49:02 +01:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
// add the torrent to the queue to be checked
|
|
|
|
m_checker_impl.m_torrents.push_back(d);
|
|
|
|
// and notify the thread that it got another
|
|
|
|
// job in its queue
|
|
|
|
m_checker_impl.m_cond.notify_one();
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
return torrent_handle(&m_impl, &m_checker_impl, ti.info_hash());
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
torrent_handle session::add_torrent(
|
|
|
|
char const* tracker_url
|
|
|
|
, sha1_hash const& info_hash
|
|
|
|
, boost::filesystem::path const& save_path
|
2005-05-13 02:39:39 +02:00
|
|
|
, entry const&
|
2005-07-10 12:42:00 +02:00
|
|
|
, bool compact_mode
|
|
|
|
, int block_size)
|
2004-06-14 01:30:42 +02:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
// make sure the block_size is an even power of 2
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (int i = 0; i < 32; ++i)
|
|
|
|
{
|
|
|
|
if (block_size & (1 << i))
|
|
|
|
{
|
|
|
|
assert((block_size & ~(1 << i)) == 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-24 02:50:52 +02:00
|
|
|
// TODO: support resume data in this case
|
2004-10-18 12:46:55 +02:00
|
|
|
assert(!save_path.empty());
|
2004-06-14 01:30:42 +02:00
|
|
|
{
|
|
|
|
// lock the checker_thread
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
// is the torrent currently being checked?
|
|
|
|
if (m_checker_impl.find_torrent(info_hash))
|
|
|
|
throw duplicate_torrent();
|
|
|
|
}
|
|
|
|
|
2004-08-30 11:08:36 +02:00
|
|
|
// lock the session
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-08-30 11:08:36 +02:00
|
|
|
|
2004-11-01 00:16:08 +01:00
|
|
|
// the metadata extension has to be enabled for this to work
|
|
|
|
assert(m_impl.m_extension_enabled
|
2006-04-25 23:04:48 +02:00
|
|
|
[extended_metadata_message]);
|
2004-11-01 00:16:08 +01:00
|
|
|
|
2004-08-30 11:08:36 +02:00
|
|
|
// is the torrent already active?
|
2006-04-25 23:04:48 +02:00
|
|
|
if (!m_impl.find_torrent(info_hash).expired())
|
2004-08-30 11:08:36 +02:00
|
|
|
throw duplicate_torrent();
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
// you cannot add new torrents to a session that is closing down
|
|
|
|
assert(!m_impl.m_abort);
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
// create the torrent and the data associated with
|
|
|
|
// the checker thread and store it before starting
|
|
|
|
// the thread
|
|
|
|
boost::shared_ptr<torrent> torrent_ptr(
|
2005-10-13 09:59:05 +02:00
|
|
|
new torrent(m_impl, m_checker_impl, tracker_url, info_hash, save_path
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_impl.m_listen_interface, compact_mode, block_size
|
|
|
|
, m_impl.m_settings));
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
m_impl.m_torrents.insert(
|
|
|
|
std::make_pair(info_hash, torrent_ptr)).first;
|
|
|
|
|
|
|
|
return torrent_handle(&m_impl, &m_checker_impl, info_hash);
|
|
|
|
}
|
|
|
|
|
2003-11-08 03:16:26 +01:00
|
|
|
void session::remove_torrent(const torrent_handle& h)
|
|
|
|
{
|
|
|
|
if (h.m_ses != &m_impl) return;
|
2004-02-29 17:39:52 +01:00
|
|
|
assert(h.m_chk == &m_checker_impl || h.m_chk == 0);
|
|
|
|
assert(h.m_ses != 0);
|
2003-11-28 18:29:27 +01:00
|
|
|
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
|
|
|
detail::session_impl::torrent_map::iterator i =
|
|
|
|
m_impl.m_torrents.find(h.m_info_hash);
|
|
|
|
if (i != m_impl.m_torrents.end())
|
2003-11-28 18:29:27 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
torrent& t = *i->second;
|
|
|
|
t.abort();
|
|
|
|
|
|
|
|
if (!t.is_paused() || t.should_request())
|
|
|
|
{
|
|
|
|
tracker_request req = t.generate_tracker_request();
|
|
|
|
assert(req.event == tracker_request::stopped);
|
|
|
|
req.listen_port = m_impl.m_listen_interface.port();
|
|
|
|
req.key = m_impl.m_key;
|
|
|
|
m_impl.m_tracker_manager.queue_request(m_impl.m_selector, req
|
|
|
|
, t.tracker_login());
|
|
|
|
|
|
|
|
if (m_impl.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_impl.m_alerts.post_alert(
|
|
|
|
tracker_announce_alert(
|
|
|
|
t.get_handle(), "tracker announce, event=stopped"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
sha1_hash i_hash = t.torrent_file().info_hash();
|
|
|
|
#endif
|
|
|
|
m_impl.m_torrents.erase(i);
|
|
|
|
assert(m_impl.m_torrents.find(i_hash) == m_impl.m_torrents.end());
|
2003-11-28 18:29:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-29 17:39:52 +01:00
|
|
|
if (h.m_chk)
|
2003-11-28 18:29:27 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
2003-11-28 18:29:27 +01:00
|
|
|
|
|
|
|
detail::piece_checker_data* d = m_checker_impl.find_torrent(h.m_info_hash);
|
|
|
|
if (d != 0)
|
|
|
|
{
|
2005-01-08 22:12:19 +01:00
|
|
|
if (d->processing) d->abort = true;
|
|
|
|
else m_checker_impl.remove_torrent(h.m_info_hash);
|
2003-11-28 18:29:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2003-11-08 03:16:26 +01:00
|
|
|
}
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
bool session::listen_on(
|
|
|
|
std::pair<int, int> const& port_range
|
|
|
|
, const char* net_interface)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-02-26 13:59:01 +01:00
|
|
|
|
2006-07-27 20:07:51 +02:00
|
|
|
tcp::endpoint new_interface;
|
|
|
|
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);
|
|
|
|
|
|
|
|
m_impl.m_listen_port_range = port_range;
|
|
|
|
|
|
|
|
// if the interface is the same and the socket is open
|
|
|
|
// don't do anything
|
|
|
|
if (new_interface == m_impl.m_listen_interface
|
|
|
|
&& m_impl.m_listen_socket) return true;
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
if (m_impl.m_listen_socket)
|
|
|
|
m_impl.m_listen_socket.reset();
|
|
|
|
|
2004-04-18 15:41:08 +02:00
|
|
|
m_impl.m_incoming_connection = false;
|
2006-07-27 20:07:51 +02:00
|
|
|
m_impl.m_listen_interface = new_interface;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
m_impl.open_listen_port();
|
|
|
|
return m_impl.m_listen_socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short session::listen_port() const
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
|
|
|
return m_impl.m_listen_interface.port();
|
2004-02-26 13:59:01 +01:00
|
|
|
}
|
|
|
|
|
2004-04-18 14:28:02 +02:00
|
|
|
session_status session::status() const
|
|
|
|
{
|
|
|
|
session_status s;
|
2004-04-18 15:41:08 +02:00
|
|
|
s.has_incoming_connections = m_impl.m_incoming_connection;
|
|
|
|
s.num_peers = (int)m_impl.m_connections.size();
|
|
|
|
|
|
|
|
s.download_rate = m_impl.m_stat.download_rate();
|
|
|
|
s.upload_rate = m_impl.m_stat.upload_rate();
|
|
|
|
|
|
|
|
s.payload_download_rate = m_impl.m_stat.download_payload_rate();
|
|
|
|
s.payload_upload_rate = m_impl.m_stat.upload_payload_rate();
|
|
|
|
|
|
|
|
s.total_download = m_impl.m_stat.total_protocol_download()
|
|
|
|
+ m_impl.m_stat.total_payload_download();
|
|
|
|
|
|
|
|
s.total_upload = m_impl.m_stat.total_protocol_upload()
|
|
|
|
+ m_impl.m_stat.total_payload_upload();
|
|
|
|
|
|
|
|
s.total_payload_download = m_impl.m_stat.total_payload_download();
|
|
|
|
s.total_payload_upload = m_impl.m_stat.total_payload_upload();
|
|
|
|
|
2004-04-18 14:28:02 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2004-02-26 13:59:01 +01:00
|
|
|
bool session::is_listening() const
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-02-26 13:59:01 +01:00
|
|
|
return m_impl.m_listen_socket;
|
|
|
|
}
|
|
|
|
|
2006-05-21 01:24:19 +02:00
|
|
|
void session::set_settings(session_settings const& s)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2006-05-21 01:24:19 +02:00
|
|
|
m_impl.set_settings(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
session_settings const& session::settings()
|
|
|
|
{
|
|
|
|
return m_impl.m_settings;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
session::~session()
|
|
|
|
{
|
|
|
|
{
|
2004-08-30 11:08:36 +02:00
|
|
|
// lock the main thread and abort it
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2003-10-23 01:00:57 +02:00
|
|
|
m_impl.m_abort = true;
|
2006-04-25 23:04:48 +02:00
|
|
|
m_impl.m_selector.interrupt();
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2006-05-28 21:03:54 +02:00
|
|
|
m_thread.join();
|
|
|
|
|
|
|
|
// it's important that the main thread is closed completely before
|
|
|
|
// the checker thread is terminated. Because all the connections
|
|
|
|
// have to be closed and removed from the torrents before they
|
|
|
|
// can be destructed. (because the weak pointers in the
|
|
|
|
// peer_connections will be invalidated when the torrents are
|
|
|
|
// destructed and then the invariant will be broken).
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
2003-10-31 05:02:51 +01:00
|
|
|
// abort the checker thread
|
|
|
|
m_checker_impl.m_abort = true;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
// abort the currently checking torrent
|
|
|
|
if (!m_checker_impl.m_torrents.empty())
|
|
|
|
{
|
2005-10-13 09:59:05 +02:00
|
|
|
m_checker_impl.m_torrents.front()->abort = true;
|
2003-10-31 05:02:51 +01:00
|
|
|
}
|
|
|
|
m_checker_impl.m_cond.notify_one();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_checker_thread.join();
|
2006-05-28 21:03:54 +02:00
|
|
|
|
|
|
|
assert(m_impl.m_torrents.empty());
|
|
|
|
assert(m_impl.m_connections.empty());
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
void session::set_max_uploads(int limit)
|
|
|
|
{
|
|
|
|
assert(limit > 0 || limit == -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-10-29 15:21:09 +02:00
|
|
|
m_impl.m_max_uploads = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session::set_max_connections(int limit)
|
|
|
|
{
|
|
|
|
assert(limit > 0 || limit == -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-10-29 15:21:09 +02:00
|
|
|
m_impl.m_max_connections = limit;
|
|
|
|
}
|
|
|
|
|
2005-11-02 17:28:39 +01:00
|
|
|
void session::set_max_half_open_connections(int limit)
|
|
|
|
{
|
|
|
|
assert(limit > 0 || limit == -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2005-11-02 17:28:39 +01:00
|
|
|
m_impl.m_half_open_limit = limit;
|
|
|
|
}
|
|
|
|
|
2003-11-09 19:17:09 +01:00
|
|
|
void session::set_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2003-11-10 14:15:41 +01:00
|
|
|
assert(bytes_per_second > 0 || bytes_per_second == -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2003-11-09 19:17:09 +01:00
|
|
|
m_impl.m_upload_rate = bytes_per_second;
|
2004-03-28 19:45:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session::set_download_rate_limit(int bytes_per_second)
|
|
|
|
{
|
|
|
|
assert(bytes_per_second > 0 || bytes_per_second == -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_impl.m_mutex);
|
2004-03-28 19:45:37 +02:00
|
|
|
m_impl.m_download_rate = bytes_per_second;
|
2003-11-09 19:17:09 +01:00
|
|
|
}
|
|
|
|
|
2003-11-29 17:34:07 +01:00
|
|
|
std::auto_ptr<alert> session::pop_alert()
|
|
|
|
{
|
2003-12-22 08:14:35 +01:00
|
|
|
if (m_impl.m_alerts.pending())
|
|
|
|
return m_impl.m_alerts.get();
|
|
|
|
else
|
|
|
|
return std::auto_ptr<alert>(0);
|
2003-11-29 17:34:07 +01:00
|
|
|
}
|
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
void session::set_severity_level(alert::severity_t s)
|
2003-12-21 18:28:27 +01:00
|
|
|
{
|
2003-12-22 08:14:35 +01:00
|
|
|
m_impl.m_alerts.set_severity(s);
|
|
|
|
}
|
2003-10-25 03:31:06 +02:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
void detail::piece_checker_data::parse_resume_data(
|
|
|
|
const entry& resume_data
|
2005-06-16 17:41:04 +02:00
|
|
|
, const torrent_info& info
|
|
|
|
, std::string& error)
|
2004-01-07 01:48:02 +01:00
|
|
|
{
|
|
|
|
// if we don't have any resume data, return
|
|
|
|
if (resume_data.type() == entry::undefined_t) return;
|
|
|
|
|
|
|
|
entry rd = resume_data;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2004-03-05 13:04:47 +01:00
|
|
|
if (rd["file-format"].string() != "libtorrent resume file")
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
|
|
|
error = "missing file format tag";
|
2004-01-07 01:48:02 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2005-06-16 17:41:04 +02:00
|
|
|
if (rd["file-version"].integer() > 1)
|
|
|
|
{
|
|
|
|
error = "incompatible file version "
|
|
|
|
+ boost::lexical_cast<std::string>(rd["file-version"].integer());
|
2004-01-07 01:48:02 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
|
|
|
// verify info_hash
|
2004-03-05 13:04:47 +01:00
|
|
|
const std::string &hash = rd["info-hash"].string();
|
2004-01-18 02:58:33 +01:00
|
|
|
std::string real_hash((char*)info.info_hash().begin(), (char*)info.info_hash().end());
|
2004-01-07 01:48:02 +01:00
|
|
|
if (hash != real_hash)
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
|
|
|
error = "mismatching info-hash: " + hash;
|
2004-01-07 01:48:02 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2004-01-17 21:04:19 +01:00
|
|
|
// the peers
|
|
|
|
|
2004-10-03 13:39:34 +02:00
|
|
|
if (rd.find_key("peers"))
|
2004-01-17 21:04:19 +01:00
|
|
|
{
|
2004-10-03 13:39:34 +02:00
|
|
|
entry::list_type& peer_list = rd["peers"].list();
|
2004-01-17 21:04:19 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
std::vector<tcp::endpoint> tmp_peers;
|
2004-10-03 13:39:34 +02:00
|
|
|
tmp_peers.reserve(peer_list.size());
|
|
|
|
for (entry::list_type::iterator i = peer_list.begin();
|
2005-06-16 17:41:04 +02:00
|
|
|
i != peer_list.end(); ++i)
|
2004-10-03 13:39:34 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
tcp::endpoint a(
|
2006-05-20 17:30:40 +02:00
|
|
|
address::from_string((*i)["ip"].string())
|
|
|
|
, (unsigned short)(*i)["port"].integer());
|
2004-10-03 13:39:34 +02:00
|
|
|
tmp_peers.push_back(a);
|
|
|
|
}
|
2004-01-17 21:04:19 +01:00
|
|
|
|
2004-10-03 13:39:34 +02:00
|
|
|
peers.swap(tmp_peers);
|
|
|
|
}
|
2004-01-17 21:04:19 +01:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
// read piece map
|
2004-03-05 13:04:47 +01:00
|
|
|
const entry::list_type& slots = rd["slots"].list();
|
2004-01-25 05:18:08 +01:00
|
|
|
if ((int)slots.size() > info.num_pieces())
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
2005-06-20 23:30:39 +02:00
|
|
|
error = "file has more slots than torrent (slots: "
|
|
|
|
+ boost::lexical_cast<std::string>(slots.size()) + " size: "
|
|
|
|
+ boost::lexical_cast<std::string>(info.num_pieces()) + " )";
|
2004-01-07 01:48:02 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2004-01-12 04:05:10 +01:00
|
|
|
std::vector<int> tmp_pieces;
|
2004-01-07 01:48:02 +01:00
|
|
|
tmp_pieces.reserve(slots.size());
|
|
|
|
for (entry::list_type::const_iterator i = slots.begin();
|
2005-06-16 17:41:04 +02:00
|
|
|
i != slots.end(); ++i)
|
2004-01-07 01:48:02 +01:00
|
|
|
{
|
2004-01-25 19:18:36 +01:00
|
|
|
int index = (int)i->integer();
|
2004-01-07 01:48:02 +01:00
|
|
|
if (index >= info.num_pieces() || index < -2)
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
2005-06-20 23:30:39 +02:00
|
|
|
error = "too high index number in slot map (index: "
|
|
|
|
+ boost::lexical_cast<std::string>(index) + " size: "
|
|
|
|
+ boost::lexical_cast<std::string>(info.num_pieces()) + ")";
|
2004-01-07 01:48:02 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
tmp_pieces.push_back(index);
|
|
|
|
}
|
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
// only bother to check the partial pieces if we have the same block size
|
|
|
|
// as in the fast resume data. If the blocksize has changed, then throw
|
|
|
|
// away all partial pieces.
|
|
|
|
std::vector<piece_picker::downloading_piece> tmp_unfinished;
|
2004-03-17 13:14:44 +01:00
|
|
|
int num_blocks_per_piece = (int)rd["blocks per piece"].integer();
|
2005-07-10 12:42:00 +02:00
|
|
|
if (num_blocks_per_piece == info.piece_length() / torrent_ptr->block_size())
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
// the unfinished pieces
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
entry::list_type& unfinished = rd["unfinished"].list();
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
tmp_unfinished.reserve(unfinished.size());
|
|
|
|
for (entry::list_type::iterator i = unfinished.begin();
|
|
|
|
i != unfinished.end(); ++i)
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
piece_picker::downloading_piece p;
|
|
|
|
|
|
|
|
p.index = (int)(*i)["piece"].integer();
|
|
|
|
if (p.index < 0 || p.index >= info.num_pieces())
|
|
|
|
{
|
|
|
|
error = "invalid piece index in unfinished piece list (index: "
|
|
|
|
+ boost::lexical_cast<std::string>(p.index) + " size: "
|
|
|
|
+ boost::lexical_cast<std::string>(info.num_pieces()) + ")";
|
|
|
|
return;
|
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
const std::string& bitmask = (*i)["bitmask"].string();
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1);
|
|
|
|
if ((int)bitmask.size() != num_bitmask_bytes)
|
2004-01-07 01:48:02 +01:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
error = "invalid size of bitmask (" + boost::lexical_cast<std::string>(bitmask.size()) + ")";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int j = 0; j < num_bitmask_bytes; ++j)
|
|
|
|
{
|
|
|
|
unsigned char bits = bitmask[j];
|
|
|
|
for (int k = 0; k < 8; ++k)
|
|
|
|
{
|
|
|
|
const int bit = j * 8 + k;
|
|
|
|
if (bits & (1 << k))
|
|
|
|
p.finished_blocks[bit] = true;
|
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
}
|
2004-01-24 18:14:03 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
if (p.finished_blocks.count() == 0) continue;
|
|
|
|
|
|
|
|
std::vector<int>::iterator slot_iter
|
|
|
|
= std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index);
|
|
|
|
if (slot_iter == tmp_pieces.end())
|
|
|
|
{
|
|
|
|
// this piece is marked as unfinished
|
|
|
|
// but doesn't have any storage
|
|
|
|
error = "piece " + boost::lexical_cast<std::string>(p.index) + " is "
|
|
|
|
"marked as unfinished, but doesn't have any storage";
|
|
|
|
return;
|
|
|
|
}
|
2004-01-24 18:14:03 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
assert(*slot_iter == p.index);
|
|
|
|
int slot_index = static_cast<int>(slot_iter - tmp_pieces.begin());
|
|
|
|
unsigned long adler
|
|
|
|
= torrent_ptr->filesystem().piece_crc(
|
|
|
|
slot_index
|
|
|
|
, torrent_ptr->block_size()
|
|
|
|
, p.finished_blocks);
|
2004-01-24 18:14:03 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
const entry& ad = (*i)["adler32"];
|
|
|
|
|
|
|
|
// crc's didn't match, don't use the resume data
|
|
|
|
if (ad.integer() != adler)
|
|
|
|
{
|
|
|
|
error = "checksum mismatch on piece " + boost::lexical_cast<std::string>(p.index);
|
|
|
|
return;
|
|
|
|
}
|
2004-03-05 13:04:47 +01:00
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
tmp_unfinished.push_back(p);
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
}
|
|
|
|
|
2004-01-17 21:04:19 +01:00
|
|
|
// verify file sizes
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2005-03-05 00:45:16 +01:00
|
|
|
std::vector<std::pair<size_type, std::time_t> > file_sizes;
|
2004-03-05 13:04:47 +01:00
|
|
|
entry::list_type& l = rd["file sizes"].list();
|
2004-01-18 02:58:33 +01:00
|
|
|
|
|
|
|
for (entry::list_type::iterator i = l.begin();
|
2005-03-05 00:45:16 +01:00
|
|
|
i != l.end(); ++i)
|
2004-01-18 02:58:33 +01:00
|
|
|
{
|
2005-03-05 00:45:16 +01:00
|
|
|
file_sizes.push_back(std::pair<size_type, std::time_t>(
|
|
|
|
i->list().front().integer()
|
|
|
|
, i->list().back().integer()));
|
2004-01-18 02:58:33 +01:00
|
|
|
}
|
2004-11-18 23:33:50 +01:00
|
|
|
|
2004-11-21 11:49:02 +01:00
|
|
|
if ((int)tmp_pieces.size() == info.num_pieces()
|
2004-11-18 23:33:50 +01:00
|
|
|
&& std::find_if(tmp_pieces.begin(), tmp_pieces.end()
|
2006-01-06 22:36:17 +01:00
|
|
|
, boost::bind<bool>(std::less<int>(), _1, 0)) == tmp_pieces.end())
|
2004-11-18 23:33:50 +01:00
|
|
|
{
|
2004-11-21 11:49:02 +01:00
|
|
|
if (info.num_files() != (int)file_sizes.size())
|
2005-06-16 17:41:04 +02:00
|
|
|
{
|
2005-06-20 23:30:39 +02:00
|
|
|
error = "the number of files does not match the torrent (num: "
|
|
|
|
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
|
|
|
+ boost::lexical_cast<std::string>(info.num_files()) + ")";
|
2004-11-18 23:33:50 +01:00
|
|
|
return;
|
2005-06-16 17:41:04 +02:00
|
|
|
}
|
2004-11-18 23:33:50 +01:00
|
|
|
|
2005-03-05 00:45:16 +01:00
|
|
|
std::vector<std::pair<size_type, std::time_t> >::iterator
|
|
|
|
fs = file_sizes.begin();
|
2004-11-18 23:33:50 +01:00
|
|
|
// the resume data says we have the entire torrent
|
|
|
|
// make sure the file sizes are the right ones
|
|
|
|
for (torrent_info::file_iterator i = info.begin_files()
|
|
|
|
, end(info.end_files()); i != end; ++i, ++fs)
|
|
|
|
{
|
2005-06-16 17:41:04 +02:00
|
|
|
if (i->size != fs->first)
|
|
|
|
{
|
|
|
|
error = "file size for '" + i->path.native_file_string() + "' was expected to be "
|
|
|
|
+ boost::lexical_cast<std::string>(i->size) + " bytes";
|
|
|
|
return;
|
|
|
|
}
|
2004-11-18 23:33:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-16 17:41:04 +02:00
|
|
|
if (!match_filesizes(info, save_path, file_sizes, &error))
|
2004-01-17 21:04:19 +01:00
|
|
|
return;
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
piece_map.swap(tmp_pieces);
|
|
|
|
unfinished_pieces.swap(tmp_unfinished);
|
|
|
|
}
|
|
|
|
catch (invalid_encoding)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
catch (type_error)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2004-03-05 20:03:02 +01:00
|
|
|
catch (file_error)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|