2006-08-01 17:27:08 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2006, Arvid Norberg
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-03-17 18:15:16 +01:00
|
|
|
#include "libtorrent/pch.hpp"
|
2007-04-05 00:27:36 +02:00
|
|
|
#include "libtorrent/socket.hpp"
|
2007-03-17 18:15:16 +01:00
|
|
|
|
2006-08-02 00:23:05 +02:00
|
|
|
#include <boost/bind.hpp>
|
2007-05-23 10:45:12 +02:00
|
|
|
#include <boost/mpl/max_element.hpp>
|
|
|
|
#include <boost/mpl/vector.hpp>
|
|
|
|
#include <boost/mpl/sizeof.hpp>
|
|
|
|
#include <boost/mpl/transform_view.hpp>
|
|
|
|
#include <boost/mpl/deref.hpp>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#include <libtorrent/io.hpp>
|
|
|
|
#include <libtorrent/invariant_check.hpp>
|
|
|
|
#include <libtorrent/kademlia/rpc_manager.hpp>
|
|
|
|
#include <libtorrent/kademlia/logging.hpp>
|
|
|
|
#include <libtorrent/kademlia/routing_table.hpp>
|
2007-05-23 10:45:12 +02:00
|
|
|
#include <libtorrent/kademlia/find_data.hpp>
|
|
|
|
#include <libtorrent/kademlia/refresh.hpp>
|
|
|
|
#include <libtorrent/kademlia/node.hpp>
|
|
|
|
#include <libtorrent/kademlia/observer.hpp>
|
2006-08-01 17:27:08 +02:00
|
|
|
#include <libtorrent/hasher.hpp>
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
using boost::shared_ptr;
|
2006-08-02 00:23:05 +02:00
|
|
|
using boost::bind;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
namespace libtorrent { namespace dht
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace io = libtorrent::detail;
|
2007-05-23 10:45:12 +02:00
|
|
|
namespace mpl = boost::mpl;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_DEFINE_LOG(rpc)
|
|
|
|
#endif
|
|
|
|
|
2007-05-23 10:45:12 +02:00
|
|
|
void intrusive_ptr_add_ref(observer const* o)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(o->m_refs >= 0);
|
|
|
|
TORRENT_ASSERT(o != 0);
|
2007-05-23 10:45:12 +02:00
|
|
|
++o->m_refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intrusive_ptr_release(observer const* o)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(o->m_refs > 0);
|
|
|
|
TORRENT_ASSERT(o != 0);
|
2007-05-23 10:45:12 +02:00
|
|
|
if (--o->m_refs == 0)
|
|
|
|
{
|
|
|
|
boost::pool<>& p = o->pool_allocator;
|
2009-01-27 09:24:48 +01:00
|
|
|
(const_cast<observer*>(o))->~observer();
|
2007-10-01 07:20:00 +02:00
|
|
|
p.free(const_cast<observer*>(o));
|
2007-05-23 10:45:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
void observer::set_target(udp::endpoint const& ep)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
// use high resolution timers for logging
|
|
|
|
m_sent = time_now_hires();
|
|
|
|
#else
|
|
|
|
m_sent = time_now();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_port = ep.port();
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (ep.address().is_v6())
|
|
|
|
{
|
|
|
|
m_is_v6 = true;
|
|
|
|
m_addr.v6 = ep.address().to_v6().to_bytes();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
m_is_v6 = false;
|
|
|
|
m_addr.v4 = ep.address().to_v4().to_bytes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
address observer::target_addr() const
|
|
|
|
{
|
|
|
|
if (m_is_v6)
|
|
|
|
return address_v6(m_addr.v6);
|
|
|
|
else
|
|
|
|
return address_v4(m_addr.v4);
|
|
|
|
}
|
|
|
|
|
|
|
|
udp::endpoint observer::target_ep() const
|
|
|
|
{
|
|
|
|
return udp::endpoint(target_addr(), m_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
node_id generate_id();
|
|
|
|
|
2007-05-23 10:45:12 +02:00
|
|
|
typedef mpl::vector<
|
2009-09-20 02:23:36 +02:00
|
|
|
find_data_observer
|
2007-05-23 10:45:12 +02:00
|
|
|
, announce_observer
|
|
|
|
, null_observer
|
|
|
|
> observer_types;
|
|
|
|
|
|
|
|
typedef mpl::max_element<
|
|
|
|
mpl::transform_view<observer_types, mpl::sizeof_<mpl::_1> >
|
|
|
|
>::type max_observer_type_iter;
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
rpc_manager::rpc_manager(node_id const& our_id
|
|
|
|
, routing_table& table, send_fun const& sf
|
|
|
|
, void* userdata)
|
2009-05-14 00:18:41 +02:00
|
|
|
: m_pool_allocator(sizeof(mpl::deref<max_observer_type_iter::base>::type), 10)
|
2009-01-27 09:24:48 +01:00
|
|
|
, m_next_transaction_id(std::rand() % max_transactions)
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_oldest_transaction_id(m_next_transaction_id)
|
|
|
|
, m_send(sf)
|
2009-09-20 02:23:36 +02:00
|
|
|
, m_userdata(userdata)
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_our_id(our_id)
|
|
|
|
, m_table(table)
|
2007-04-05 00:27:36 +02:00
|
|
|
, m_timer(time_now())
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_random_number(generate_id())
|
2007-01-29 08:39:33 +01:00
|
|
|
, m_destructing(false)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
std::srand(time(0));
|
2008-12-23 21:04:12 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "Constructing";
|
|
|
|
TORRENT_LOG(rpc) << " announce_observer: " << sizeof(announce_observer);
|
|
|
|
TORRENT_LOG(rpc) << " null_observer: " << sizeof(null_observer);
|
2009-09-20 02:23:36 +02:00
|
|
|
|
|
|
|
#define PRINT_OFFSETOF(x, y) TORRENT_LOG(rpc) << " +" << offsetof(x, y) << ": " #y
|
|
|
|
|
|
|
|
TORRENT_LOG(rpc) << " observer: " << sizeof(observer);
|
|
|
|
PRINT_OFFSETOF(observer, pool_allocator);
|
|
|
|
PRINT_OFFSETOF(observer, m_sent);
|
|
|
|
PRINT_OFFSETOF(observer, m_refs);
|
|
|
|
PRINT_OFFSETOF(observer, m_addr);
|
|
|
|
PRINT_OFFSETOF(observer, m_port);
|
|
|
|
|
|
|
|
TORRENT_LOG(rpc) << " find_data_observer: " << sizeof(find_data_observer);
|
|
|
|
PRINT_OFFSETOF(find_data_observer, m_algorithm);
|
|
|
|
PRINT_OFFSETOF(find_data_observer, m_self);
|
|
|
|
|
|
|
|
#undef PRINT_OFFSETOF
|
2008-12-23 21:04:12 +01:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
rpc_manager::~rpc_manager()
|
|
|
|
{
|
2008-01-14 18:25:08 +01:00
|
|
|
TORRENT_ASSERT(!m_destructing);
|
2007-01-29 08:39:33 +01:00
|
|
|
m_destructing = true;
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "Destructing";
|
|
|
|
#endif
|
2007-01-29 08:39:33 +01:00
|
|
|
std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
|
|
|
|
, bind(&observer::abort, _1));
|
|
|
|
|
|
|
|
for (transactions_t::iterator i = m_transactions.begin()
|
|
|
|
, end(m_transactions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (*i) (*i)->abort();
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2008-01-13 05:24:10 +01:00
|
|
|
size_t rpc_manager::allocation_size() const
|
|
|
|
{
|
|
|
|
size_t s = sizeof(mpl::deref<max_observer_type_iter::base>::type);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
void rpc_manager::check_invariant() const
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id >= 0);
|
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id < max_transactions);
|
|
|
|
TORRENT_ASSERT(m_next_transaction_id >= 0);
|
|
|
|
TORRENT_ASSERT(m_next_transaction_id < max_transactions);
|
|
|
|
TORRENT_ASSERT(!m_transactions[m_next_transaction_id]);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2006-08-02 00:23:05 +02:00
|
|
|
for (int i = (m_next_transaction_id + 1) % max_transactions;
|
|
|
|
i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_transactions[i]);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-05-08 02:22:17 +02:00
|
|
|
void rpc_manager::unreachable(udp::endpoint const& ep)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << time_now_string() << " PORT_UNREACHABLE [ ip: " << ep << " ]";
|
|
|
|
#endif
|
|
|
|
int num_active = m_oldest_transaction_id < m_next_transaction_id
|
|
|
|
? m_next_transaction_id - m_oldest_transaction_id
|
2008-08-30 01:00:57 +02:00
|
|
|
: max_transactions - m_oldest_transaction_id + m_next_transaction_id;
|
2008-05-08 02:22:17 +02:00
|
|
|
TORRENT_ASSERT((m_oldest_transaction_id + num_active) % max_transactions
|
|
|
|
== m_next_transaction_id);
|
|
|
|
int tid = m_oldest_transaction_id;
|
|
|
|
for (int i = 0; i < num_active; ++i, ++tid)
|
|
|
|
{
|
|
|
|
if (tid >= max_transactions) tid = 0;
|
|
|
|
observer_ptr const& o = m_transactions[tid];
|
|
|
|
if (!o) continue;
|
2009-05-14 00:18:41 +02:00
|
|
|
if (o->target_ep() != ep) continue;
|
2008-05-08 02:22:17 +02:00
|
|
|
observer_ptr ptr = m_transactions[tid];
|
|
|
|
m_transactions[tid] = 0;
|
|
|
|
if (tid == m_oldest_transaction_id)
|
|
|
|
{
|
|
|
|
++m_oldest_transaction_id;
|
|
|
|
if (m_oldest_transaction_id >= max_transactions)
|
|
|
|
m_oldest_transaction_id = 0;
|
|
|
|
}
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << " found transaction [ tid: " << tid << " ]";
|
|
|
|
#endif
|
|
|
|
ptr->timeout();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
// defined in node.cpp
|
|
|
|
void incoming_error(entry& e, char const* msg);
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
bool rpc_manager::incoming(msg const& m)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-01-29 08:39:33 +01:00
|
|
|
if (m_destructing) return false;
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
// we only deal with replies, not queries
|
|
|
|
TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r");
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
// if we don't have the transaction id in our
|
|
|
|
// request list, ignore the packet
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
std::string transaction_id = m.message.dict_find_string_value("t");
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
std::string::const_iterator i = transaction_id.begin();
|
|
|
|
int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i);
|
|
|
|
|
|
|
|
observer_ptr o;
|
|
|
|
|
|
|
|
if (tid >= (int)m_transactions.size() || tid < 0)
|
|
|
|
{
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
|
|
|
|
<< transaction_id.size() << " from " << m.addr;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
entry e;
|
|
|
|
incoming_error(e, "invalid transaction id");
|
|
|
|
m_send(m_userdata, e, m.addr, 0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
o = m_transactions[tid];
|
|
|
|
|
|
|
|
if (!o)
|
|
|
|
{
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(rpc) << "Reply to a timed out request "
|
|
|
|
<< tid << " from " << m.addr;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
return false;
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
if (m.addr.address() != o->target_addr())
|
|
|
|
{
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
|
|
|
|
<< tid << " from " << m.addr << " expected: " << o->target_addr();
|
2007-11-24 22:38:46 +01:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-11-24 22:38:46 +01:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
std::ofstream reply_stats("round_trip_ms.log", std::ios::app);
|
|
|
|
reply_stats << m.addr << "\t" << total_milliseconds(time_now_hires() - o->sent())
|
|
|
|
<< std::endl;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
|
|
|
|
lazy_entry const* ret_ent = m.message.dict_find_dict("r");
|
|
|
|
if (ret_ent == 0)
|
|
|
|
{
|
|
|
|
entry e;
|
|
|
|
incoming_error(e, "missing 'r' key");
|
|
|
|
m_send(m_userdata, e, m.addr, 0);
|
|
|
|
return false;
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
|
|
|
|
lazy_entry const* node_id_ent = ret_ent->dict_find_string("id");
|
|
|
|
if (node_id_ent == 0 || node_id_ent->string_length() != 20)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2009-09-20 02:23:36 +02:00
|
|
|
entry e;
|
|
|
|
incoming_error(e, "missing 'id' key");
|
|
|
|
m_send(m_userdata, e, m.addr, 0);
|
|
|
|
return false;
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "Reply with transaction id: "
|
|
|
|
<< tid << " from " << m.addr;
|
|
|
|
#endif
|
|
|
|
o->reply(m);
|
|
|
|
m_transactions[tid] = 0;
|
|
|
|
return m_table.node_seen(node_id(node_id_ent->string_ptr()), m.addr);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
time_duration rpc_manager::tick()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2009-09-29 19:06:08 +02:00
|
|
|
const static int short_timeout = 2;
|
|
|
|
const static int timeout = 10;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-29 19:06:08 +02:00
|
|
|
// look for observers that have timed out
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-29 19:06:08 +02:00
|
|
|
if (m_next_transaction_id == m_oldest_transaction_id) return seconds(short_timeout);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-09-15 07:05:26 +02:00
|
|
|
std::vector<observer_ptr> timeouts;
|
|
|
|
|
2009-09-29 19:06:08 +02:00
|
|
|
time_duration ret = seconds(short_timeout);
|
|
|
|
ptime now = time_now();
|
2007-01-29 08:39:33 +01:00
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
for (;m_next_transaction_id != m_oldest_transaction_id;
|
|
|
|
m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id >= 0);
|
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id < max_transactions);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2007-05-23 10:45:12 +02:00
|
|
|
observer_ptr o = m_transactions[m_oldest_transaction_id];
|
2006-08-01 17:27:08 +02:00
|
|
|
if (!o) continue;
|
|
|
|
|
2009-09-29 19:06:08 +02:00
|
|
|
// if we reach an observer that hasn't timed out
|
|
|
|
// break, because every observer after this one will
|
|
|
|
// also not have timed out yet
|
|
|
|
time_duration diff = now - o->sent();
|
|
|
|
if (diff < seconds(timeout))
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2009-09-29 19:06:08 +02:00
|
|
|
ret = seconds(timeout) - diff;
|
|
|
|
break;
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2009-05-14 22:38:42 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2007-01-04 16:44:23 +01:00
|
|
|
try
|
|
|
|
{
|
2009-05-14 22:38:42 +02:00
|
|
|
#endif
|
2007-05-23 10:45:12 +02:00
|
|
|
m_transactions[m_oldest_transaction_id] = 0;
|
2007-11-24 22:38:46 +01:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "Timing out transaction id: "
|
2009-05-14 00:18:41 +02:00
|
|
|
<< m_oldest_transaction_id << " from " << o->target_ep();
|
2007-11-24 22:38:46 +01:00
|
|
|
#endif
|
2007-01-29 08:39:33 +01:00
|
|
|
timeouts.push_back(o);
|
2009-05-14 22:38:42 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2007-01-04 16:44:23 +01:00
|
|
|
} catch (std::exception) {}
|
2009-05-14 22:38:42 +02:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2007-01-29 08:39:33 +01:00
|
|
|
|
|
|
|
std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
|
|
|
|
timeouts.clear();
|
2009-09-29 19:06:08 +02:00
|
|
|
|
2007-01-29 08:39:33 +01:00
|
|
|
// clear the aborted transactions, will likely
|
|
|
|
// generate new requests. We need to swap, since the
|
|
|
|
// destrutors may add more observers to the m_aborted_transactions
|
2008-01-14 18:25:08 +01:00
|
|
|
std::vector<observer_ptr>().swap(m_aborted_transactions);
|
2009-09-29 19:06:08 +02:00
|
|
|
|
|
|
|
for (int i = m_oldest_transaction_id; i != m_next_transaction_id;
|
|
|
|
i = (i + 1) % max_transactions)
|
|
|
|
{
|
|
|
|
observer_ptr o = m_transactions[i];
|
|
|
|
if (!o) continue;
|
|
|
|
|
|
|
|
// if we reach an observer that hasn't timed out
|
|
|
|
// break, because every observer after this one will
|
|
|
|
// also not have timed out yet
|
|
|
|
time_duration diff = now - o->sent();
|
|
|
|
if (diff < seconds(short_timeout))
|
|
|
|
{
|
|
|
|
ret = seconds(short_timeout) - diff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: don't call short_timeout() again if we've
|
|
|
|
// already called it once
|
|
|
|
timeouts.push_back(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::short_timeout, _1));
|
|
|
|
|
2008-09-15 07:05:26 +02:00
|
|
|
return ret;
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2007-05-23 10:45:12 +02:00
|
|
|
unsigned int rpc_manager::new_transaction_id(observer_ptr o)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
unsigned int tid = m_next_transaction_id;
|
|
|
|
m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
|
|
|
|
if (m_transactions[m_next_transaction_id])
|
|
|
|
{
|
2007-01-29 08:39:33 +01:00
|
|
|
// moving the observer into the set of aborted transactions
|
|
|
|
// it will prevent it from spawning new requests right now,
|
|
|
|
// since that would break the invariant
|
2007-11-24 22:38:46 +01:00
|
|
|
observer_ptr o = m_transactions[m_next_transaction_id];
|
|
|
|
m_aborted_transactions.push_back(o);
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "[new_transaction_id] Aborting message with transaction id: "
|
2009-05-14 00:18:41 +02:00
|
|
|
<< m_next_transaction_id << " sent to " << o->target_ep()
|
2009-09-20 02:23:36 +02:00
|
|
|
<< " " << total_seconds(time_now() - o->sent()) << " seconds ago";
|
2007-11-24 22:38:46 +01:00
|
|
|
#endif
|
2007-05-23 10:45:12 +02:00
|
|
|
m_transactions[m_next_transaction_id] = 0;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id == m_next_transaction_id);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_transactions[tid]);
|
2007-01-29 08:39:33 +01:00
|
|
|
m_transactions[tid] = o;
|
2006-08-01 17:27:08 +02:00
|
|
|
if (m_oldest_transaction_id == m_next_transaction_id)
|
|
|
|
{
|
|
|
|
m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
|
2006-08-02 00:23:05 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
|
|
|
|
" messages! limit: " << (int)max_transactions;
|
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
update_oldest_transaction_id();
|
|
|
|
}
|
|
|
|
|
|
|
|
return tid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpc_manager::update_oldest_transaction_id()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_oldest_transaction_id != m_next_transaction_id);
|
2006-08-01 17:27:08 +02:00
|
|
|
while (!m_transactions[m_oldest_transaction_id])
|
|
|
|
{
|
|
|
|
m_oldest_transaction_id = (m_oldest_transaction_id + 1)
|
|
|
|
% max_transactions;
|
|
|
|
if (m_oldest_transaction_id == m_next_transaction_id)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
void rpc_manager::add_our_id(entry& e)
|
|
|
|
{
|
|
|
|
e["id"] = m_our_id.to_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpc_manager::invoke(entry& e, udp::endpoint target_addr
|
2007-05-23 10:45:12 +02:00
|
|
|
, observer_ptr o)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-01-29 08:39:33 +01:00
|
|
|
if (m_destructing)
|
|
|
|
{
|
|
|
|
o->abort();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
e["y"] = "q";
|
|
|
|
entry& a = e["a"];
|
|
|
|
add_our_id(a);
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_transactions[m_next_transaction_id]);
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2007-04-02 08:49:15 +02:00
|
|
|
int potential_new_id = m_next_transaction_id;
|
|
|
|
#endif
|
2009-05-14 22:38:42 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2007-01-29 08:39:33 +01:00
|
|
|
try
|
|
|
|
{
|
2009-05-14 22:38:42 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
std::string transaction_id;
|
|
|
|
transaction_id.resize(2);
|
|
|
|
char* out = &transaction_id[0];
|
2007-01-29 08:39:33 +01:00
|
|
|
io::write_uint16(m_next_transaction_id, out);
|
2009-09-20 02:23:36 +02:00
|
|
|
e["t"] = transaction_id;
|
2007-01-29 08:39:33 +01:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
o->set_target(target_addr);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-05-14 22:38:42 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(rpc) << "Invoking " << e["q"].string() << " -> " << target_addr;
|
2009-05-14 22:38:42 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
m_send(m_userdata, e, target_addr, 1);
|
2007-01-29 08:39:33 +01:00
|
|
|
new_transaction_id(o);
|
2009-05-14 22:38:42 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2007-01-29 08:39:33 +01:00
|
|
|
}
|
2007-03-06 18:27:17 +01:00
|
|
|
catch (std::exception& e)
|
2007-01-29 08:39:33 +01:00
|
|
|
{
|
2007-03-10 21:23:16 +01:00
|
|
|
// m_send may fail with "no route to host"
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(potential_new_id == m_next_transaction_id);
|
2007-04-02 08:49:15 +02:00
|
|
|
o->abort();
|
2007-01-29 08:39:33 +01:00
|
|
|
}
|
2009-05-14 22:38:42 +02:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
/*
|
2007-05-12 03:52:25 +02:00
|
|
|
void rpc_manager::reply(msg& m)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-01-29 08:39:33 +01:00
|
|
|
if (m_destructing) return;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m.reply);
|
2006-08-01 17:27:08 +02:00
|
|
|
m.id = m_our_id;
|
|
|
|
|
|
|
|
m_send(m);
|
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
*/
|
2006-08-01 17:27:08 +02:00
|
|
|
} } // namespace libtorrent::dht
|
|
|
|
|