00001
00002
00003
00004
00005
00006
00007
00008 #include <libtorrent/kademlia/traversal_algorithm.hpp>
00009 #include <libtorrent/kademlia/routing_table.hpp>
00010 #include <libtorrent/kademlia/rpc_manager.hpp>
00011
00012 #include <boost/bind.hpp>
00013
00014 using boost::bind;
00015 using asio::ip::udp;
00016
00017 namespace libtorrent { namespace dht
00018 {
00019 #ifdef TORRENT_DHT_VERBOSE_LOGGING
00020 TORRENT_DEFINE_LOG(traversal)
00021 #endif
00022
00023 void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
00024 {
00025 if (m_failed.find(addr) != m_failed.end()) return;
00026
00027 result const entry(id, addr, flags);
00028
00029 std::vector<result>::iterator i = std::lower_bound(
00030 m_results.begin()
00031 , m_results.end()
00032 , entry
00033 , bind(
00034 compare_ref
00035 , bind(&result::id, _1)
00036 , bind(&result::id, _2)
00037 , m_target
00038 )
00039 );
00040
00041 if (i == m_results.end() || i->id != id)
00042 {
00043 assert(std::find_if(m_results.begin(), m_results.end()
00044 , bind(std::equal_to<node_id>()
00045 , bind(&result::id, _1), id)) == m_results.end());
00046 #ifdef TORRENT_DHT_VERBOSE_LOGGING
00047 TORRENT_LOG(traversal) << "adding result: " << id << " " << addr;
00048 #endif
00049 m_results.insert(i, entry);
00050 }
00051 }
00052
00053 void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
00054 {
00055 add_entry(id, addr, 0);
00056 }
00057
00058 void traversal_algorithm::finished(node_id const& id)
00059 {
00060 --m_invoke_count;
00061 add_requests();
00062 if (m_invoke_count == 0) done();
00063 }
00064
00065 void traversal_algorithm::failed(node_id const& id, bool prevent_request)
00066 {
00067 m_invoke_count--;
00068
00069 std::vector<result>::iterator i = std::find_if(
00070 m_results.begin()
00071 , m_results.end()
00072 , bind(
00073 std::equal_to<node_id>()
00074 , bind(&result::id, _1)
00075 , id
00076 )
00077 );
00078
00079 assert(i != m_results.end());
00080
00081 if (i != m_results.end())
00082 {
00083 assert(i->flags & result::queried);
00084 m_failed.insert(i->addr);
00085 #ifdef TORRENT_DHT_VERBOSE_LOGGING
00086 TORRENT_LOG(traversal) << "failed: " << i->id << " " << i->addr;
00087 #endif
00088 m_results.erase(i);
00089 }
00090 if (prevent_request)
00091 {
00092 --m_branch_factor;
00093 if (m_branch_factor <= 0) m_branch_factor = 1;
00094 }
00095 else
00096 {
00097 m_table.node_failed(id);
00098 }
00099 add_requests();
00100 if (m_invoke_count == 0) done();
00101 }
00102
00103 namespace
00104 {
00105 bool bitwise_nand(unsigned char lhs, unsigned char rhs)
00106 {
00107 return (lhs & rhs) == 0;
00108 }
00109 }
00110
00111 void traversal_algorithm::add_requests()
00112 {
00113 while (m_invoke_count < m_branch_factor)
00114 {
00115
00116
00117 std::vector<result>::iterator i = std::find_if(
00118 m_results.begin()
00119 , last_iterator()
00120 , bind(
00121 &bitwise_nand
00122 , bind(&result::flags, _1)
00123 , (unsigned char)result::queried
00124 )
00125 );
00126 #ifdef TORRENT_DHT_VERBOSE_LOGGING
00127 TORRENT_LOG(traversal) << "nodes left (" << this << "): " << (last_iterator() - i);
00128 #endif
00129
00130 if (i == last_iterator()) break;
00131
00132 try
00133 {
00134 invoke(i->id, i->addr);
00135 ++m_invoke_count;
00136 i->flags |= result::queried;
00137 }
00138 catch (std::exception& e) {}
00139 }
00140 }
00141
00142 std::vector<traversal_algorithm::result>::iterator traversal_algorithm::last_iterator()
00143 {
00144 return (int)m_results.size() >= m_max_results ?
00145 m_results.begin() + m_max_results
00146 : m_results.end();
00147 }
00148
00149 } }
00150