00001
00002
00003
00004
00005
00006
00007
00008 #include <vector>
00009 #include <deque>
00010 #include <algorithm>
00011 #include <functional>
00012 #include <numeric>
00013 #include <boost/cstdint.hpp>
00014 #include <boost/bind.hpp>
00015 #include <boost/date_time/posix_time/posix_time.hpp>
00016
00017 #include "libtorrent/kademlia/routing_table.hpp"
00018 #include "libtorrent/kademlia/node_id.hpp"
00019 #include "libtorrent/session_settings.hpp"
00020
00021 using boost::bind;
00022 using boost::uint8_t;
00023
00024 using boost::posix_time::second_clock;
00025 using boost::posix_time::minutes;
00026 using boost::posix_time::seconds;
00027 using boost::posix_time::hours;
00028
00029 namespace pt = boost::posix_time;
00030
00031 namespace libtorrent { namespace dht
00032 {
00033
00034 using asio::ip::udp;
00035 typedef asio::ip::address_v4 address;
00036
00037 routing_table::routing_table(node_id const& id, int bucket_size
00038 , dht_settings const& settings)
00039 : m_bucket_size(bucket_size)
00040 , m_settings(settings)
00041 , m_id(id)
00042 , m_lowest_active_bucket(160)
00043 {
00044
00045
00046 for (int i = 0; i < 160; ++i)
00047 m_bucket_activity[i] = second_clock::universal_time() - seconds(15*60 - i*5);
00048 }
00049
00050 boost::tuple<int, int> routing_table::size() const
00051 {
00052 int nodes = 0;
00053 int replacements = 0;
00054 for (table_t::const_iterator i = m_buckets.begin()
00055 , end(m_buckets.end()); i != end; ++i)
00056 {
00057 nodes += i->first.size();
00058 replacements += i->second.size();
00059 }
00060 return boost::make_tuple(nodes, replacements);
00061 }
00062
00063 void routing_table::print_state(std::ostream& os) const
00064 {
00065 os << "kademlia routing table state\n"
00066 << "bucket_size: " << m_bucket_size << "\n"
00067 << "node_id: " << m_id << "\n\n";
00068
00069 os << "number of nodes per bucket:\n"
00070 "live\n";
00071 for (int k = 0; k < 8; ++k)
00072 {
00073 for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
00074 i != end; ++i)
00075 {
00076 os << (int(i->first.size()) > (7 - k) ? "|" : " ");
00077 }
00078 os << "\n";
00079 }
00080 for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
00081 i != end; ++i)
00082 {
00083 os << "+";
00084 }
00085 os << "\n";
00086 for (int k = 0; k < 8; ++k)
00087 {
00088 for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
00089 i != end; ++i)
00090 {
00091 os << (int(i->second.size()) > k ? "|" : " ");
00092 }
00093 os << "\n";
00094 }
00095 os << "cached\n-----------\n";
00096
00097 os << "nodes:\n";
00098 for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
00099 i != end; ++i)
00100 {
00101 int bucket_index = int(i - m_buckets.begin());
00102 os << "bucket " << bucket_index << " "
00103 << to_simple_string(m_bucket_activity[bucket_index])
00104 << " " << (bucket_index >= m_lowest_active_bucket?"active":"inactive")
00105 << "\n";
00106 for (bucket_t::const_iterator j = i->first.begin()
00107 , end(i->first.end()); j != end; ++j)
00108 {
00109 os << "ip: " << j->addr << " fails: " << j->fail_count
00110 << " id: " << j->id << "\n";
00111 }
00112 }
00113 }
00114
00115 void routing_table::touch_bucket(int bucket)
00116 {
00117 m_bucket_activity[bucket] = second_clock::universal_time();
00118 }
00119
00120 boost::posix_time::ptime routing_table::next_refresh(int bucket)
00121 {
00122 assert(bucket < 160);
00123 assert(bucket >= 0);
00124
00125
00126 if (bucket <= m_lowest_active_bucket && bucket > 0)
00127 return second_clock::universal_time() + minutes(15);
00128 return m_bucket_activity[bucket] + minutes(15);
00129 }
00130
00131 void routing_table::replacement_cache(bucket_t& nodes) const
00132 {
00133 for (table_t::const_iterator i = m_buckets.begin()
00134 , end(m_buckets.end()); i != end; ++i)
00135 {
00136 std::copy(i->second.begin(), i->second.end()
00137 , std::back_inserter(nodes));
00138 }
00139 }
00140
00141 bool routing_table::need_node(node_id const& id)
00142 {
00143 int bucket_index = distance_exp(m_id, id);
00144 assert(bucket_index < (int)m_buckets.size());
00145 assert(bucket_index >= 0);
00146 bucket_t& b = m_buckets[bucket_index].first;
00147 bucket_t& rb = m_buckets[bucket_index].second;
00148
00149
00150
00151
00152 if ((int)rb.size() >= m_bucket_size) return false;
00153
00154
00155 if (std::find_if(b.begin(), b.end(), bind(std::equal_to<node_id>()
00156 , bind(&node_entry::id, _1), id)) != b.end()) return false;
00157
00158 if (std::find_if(rb.begin(), rb.end(), bind(std::equal_to<node_id>()
00159 , bind(&node_entry::id, _1), id)) != rb.end()) return false;
00160
00161 return true;
00162 }
00163
00164 void routing_table::node_failed(node_id const& id)
00165 {
00166 int bucket_index = distance_exp(m_id, id);
00167 assert(bucket_index < (int)m_buckets.size());
00168 assert(bucket_index >= 0);
00169 bucket_t& b = m_buckets[bucket_index].first;
00170 bucket_t& rb = m_buckets[bucket_index].second;
00171
00172 bucket_t::iterator i = std::find_if(b.begin(), b.end()
00173 , bind(std::equal_to<node_id>()
00174 , bind(&node_entry::id, _1), id));
00175
00176 if (i == b.end()) return;
00177
00178
00179 if (bucket_index == 0) return;
00180
00181 if (rb.empty())
00182 {
00183 ++i->fail_count;
00184 if (i->fail_count >= m_settings.max_fail_count)
00185 {
00186 b.erase(i);
00187 assert(m_lowest_active_bucket <= bucket_index);
00188 while (m_buckets[m_lowest_active_bucket].first.empty()
00189 && m_lowest_active_bucket < 160)
00190 {
00191 ++m_lowest_active_bucket;
00192 }
00193 }
00194 return;
00195 }
00196
00197 b.erase(i);
00198 b.push_back(rb.back());
00199 rb.erase(rb.end() - 1);
00200 }
00201
00202 void routing_table::add_router_node(udp::endpoint router)
00203 {
00204 m_router_nodes.insert(router);
00205 }
00206
00207 bool routing_table::node_seen(node_id const& id, udp::endpoint addr)
00208 {
00209 if (m_router_nodes.find(addr) != m_router_nodes.end()) return false;
00210 int bucket_index = distance_exp(m_id, id);
00211 assert(bucket_index < (int)m_buckets.size());
00212 assert(bucket_index >= 0);
00213 bucket_t& b = m_buckets[bucket_index].first;
00214
00215 bucket_t::iterator i = std::find_if(b.begin(), b.end()
00216 , bind(std::equal_to<node_id>()
00217 , bind(&node_entry::id, _1), id));
00218
00219 bool ret = need_bootstrap();
00220
00221 m_bucket_activity[bucket_index] = second_clock::universal_time();
00222
00223 if (i != b.end())
00224 {
00225
00226
00227
00228
00229
00230
00231
00232 b.erase(i);
00233 b.push_back(node_entry(id, addr));
00234
00235 return ret;
00236 }
00237
00238
00239
00240
00241
00242 if ((int)b.size() < m_bucket_size)
00243 {
00244 b.push_back(node_entry(id, addr));
00245
00246
00247 if (bucket_index < m_lowest_active_bucket
00248 && bucket_index > 0)
00249 m_lowest_active_bucket = bucket_index;
00250
00251 return ret;
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 i = std::max_element(b.begin(), b.end()
00263 , bind(std::less<int>()
00264 , bind(&node_entry::fail_count, _1)
00265 , bind(&node_entry::fail_count, _2)));
00266
00267 if (i != b.end() && i->fail_count > 0)
00268 {
00269
00270
00271 b.erase(i);
00272 b.push_back(node_entry(id, addr));
00273
00274 return ret;
00275 }
00276
00277
00278
00279
00280
00281
00282 bucket_t& rb = m_buckets[bucket_index].second;
00283
00284 i = std::find_if(rb.begin(), rb.end()
00285 , bind(std::equal_to<node_id>()
00286 , bind(&node_entry::id, _1), id));
00287
00288
00289
00290 if (i != rb.end()) return ret;
00291
00292 if ((int)rb.size() > m_bucket_size) rb.erase(rb.begin());
00293 rb.push_back(node_entry(id, addr));
00294
00295 return ret;
00296 }
00297
00298 bool routing_table::need_bootstrap() const
00299 {
00300 for (const_iterator i = begin(); i != end(); ++i)
00301 {
00302 if (i->fail_count == 0) return false;
00303 }
00304 return true;
00305 }
00306
00307 void routing_table::find_node(node_id const& target
00308 , std::vector<node_entry>& l, bool include_self, int count)
00309 {
00310 l.clear();
00311 if (count == 0) count = m_bucket_size;
00312 l.reserve(count);
00313
00314 int bucket_index = distance_exp(m_id, target);
00315 bucket_t& b = m_buckets[bucket_index].first;
00316
00317
00318
00319 std::remove_copy_if(b.begin(), b.end(), std::back_inserter(l)
00320 , bind(&node_entry::fail_count, _1));
00321 assert((int)l.size() <= count);
00322
00323 if ((int)l.size() == count)
00324 {
00325 assert(std::count_if(l.begin(), l.end()
00326 , boost::bind(std::not_equal_to<int>()
00327 , boost::bind(&node_entry::fail_count, _1), 0)) == 0);
00328 return;
00329 }
00330
00331
00332
00333
00334
00335
00336 bucket_t tmpb;
00337 for (int i = include_self?0:1; i < count; ++i)
00338 {
00339 bucket_t& b = m_buckets[i].first;
00340 std::remove_copy_if(b.begin(), b.end(), std::back_inserter(tmpb)
00341 , bind(&node_entry::fail_count, _1));
00342 }
00343
00344 std::random_shuffle(tmpb.begin(), tmpb.end());
00345 size_t to_copy = (std::min)(m_bucket_size - l.size()
00346 , tmpb.size());
00347 std::copy(tmpb.begin(), tmpb.begin() + to_copy
00348 , std::back_inserter(l));
00349
00350 assert((int)l.size() <= m_bucket_size);
00351
00352
00353
00354
00355 if ((int)l.size() == count
00356 || bucket_index == (int)m_buckets.size() - 1)
00357 {
00358 assert(std::count_if(l.begin(), l.end()
00359 , boost::bind(std::not_equal_to<int>()
00360 , boost::bind(&node_entry::fail_count, _1), 0)) == 0);
00361 return;
00362 }
00363
00364 for (size_t i = bucket_index + 1; i < m_buckets.size(); ++i)
00365 {
00366 bucket_t& b = m_buckets[i].first;
00367
00368 std::remove_copy_if(b.begin(), b.end(), std::back_inserter(l)
00369 , bind(&node_entry::fail_count, _1));
00370 if ((int)l.size() >= count)
00371 {
00372 l.erase(l.begin() + count, l.end());
00373 assert(std::count_if(l.begin(), l.end()
00374 , boost::bind(std::not_equal_to<int>()
00375 , boost::bind(&node_entry::fail_count, _1), 0)) == 0);
00376 return;
00377 }
00378 }
00379 assert((int)l.size() == count
00380 || std::distance(l.begin(), l.end()) < m_bucket_size);
00381 assert((int)l.size() <= count);
00382
00383 assert(std::count_if(l.begin(), l.end()
00384 , boost::bind(std::not_equal_to<int>()
00385 , boost::bind(&node_entry::fail_count, _1), 0)) == 0);
00386 }
00387
00388 routing_table::iterator routing_table::begin() const
00389 {
00390 return iterator(m_buckets.begin(), m_buckets.end());
00391 }
00392
00393 routing_table::iterator routing_table::end() const
00394 {
00395 return iterator(m_buckets.end(), m_buckets.end());
00396 }
00397
00398 } }
00399