delete_files bug fix
[libtorrent.git] / src / kademlia / traversal_algorithm.cpp
blob138d429050d9d61faf7712181f4feadc8f7dfe76
1 /*
3 Copyright (c) 2006, Arvid Norberg & Daniel Wallin
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include "libtorrent/pch.hpp"
35 #include <libtorrent/kademlia/traversal_algorithm.hpp>
36 #include <libtorrent/kademlia/routing_table.hpp>
37 #include <libtorrent/kademlia/rpc_manager.hpp>
39 #include <boost/bind.hpp>
41 using boost::bind;
43 namespace libtorrent { namespace dht
45 #ifdef TORRENT_DHT_VERBOSE_LOGGING
46 TORRENT_DEFINE_LOG(traversal)
47 #endif
49 void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
51 if (m_failed.find(addr) != m_failed.end()) return;
53 result entry(id, addr, flags);
54 if (entry.id.is_all_zeros())
56 entry.id = generate_id();
57 entry.flags |= result::no_id;
60 std::vector<result>::iterator i = std::lower_bound(
61 m_results.begin()
62 , m_results.end()
63 , entry
64 , bind(
65 compare_ref
66 , bind(&result::id, _1)
67 , bind(&result::id, _2)
68 , m_target
72 if (i == m_results.end() || i->id != id)
74 TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
75 , bind(&result::id, _1) == id) == m_results.end());
76 #ifdef TORRENT_DHT_VERBOSE_LOGGING
77 TORRENT_LOG(traversal) << "adding result: " << id << " " << addr;
78 #endif
79 m_results.insert(i, entry);
83 boost::pool<>& traversal_algorithm::allocator() const
85 return m_rpc.allocator();
88 void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
90 #ifdef TORRENT_DHT_VERBOSE_LOGGING
91 if (id.is_all_zeros())
92 TORRENT_LOG(traversal) << time_now_string() << " WARNING: node returned a list which included a node with id 0";
93 #endif
94 add_entry(id, addr, 0);
97 void traversal_algorithm::finished(node_id const& id)
99 --m_invoke_count;
100 add_requests();
101 if (m_invoke_count == 0) done();
104 // prevent request means that the total number of requests has
105 // overflown. This query failed because it was the oldest one.
106 // So, if this is true, don't make another request
107 void traversal_algorithm::failed(node_id const& id, bool prevent_request)
109 m_invoke_count--;
111 TORRENT_ASSERT(!id.is_all_zeros());
112 std::vector<result>::iterator i = std::find_if(
113 m_results.begin()
114 , m_results.end()
115 , bind(
116 std::equal_to<node_id>()
117 , bind(&result::id, _1)
118 , id
122 TORRENT_ASSERT(i != m_results.end());
124 if (i != m_results.end())
126 TORRENT_ASSERT(i->flags & result::queried);
127 m_failed.insert(i->addr);
128 #ifdef TORRENT_DHT_VERBOSE_LOGGING
129 TORRENT_LOG(traversal) << "failed: " << i->id << " " << i->addr;
130 #endif
131 // don't tell the routing table about
132 // node ids that we just generated ourself
133 if ((i->flags & result::no_id) == 0)
134 m_table.node_failed(id);
135 m_results.erase(i);
137 if (prevent_request)
139 --m_branch_factor;
140 if (m_branch_factor <= 0) m_branch_factor = 1;
142 add_requests();
143 if (m_invoke_count == 0) done();
146 namespace
148 bool bitwise_nand(unsigned char lhs, unsigned char rhs)
150 return (lhs & rhs) == 0;
154 void traversal_algorithm::add_requests()
156 while (m_invoke_count < m_branch_factor)
158 // Find the first node that hasn't already been queried.
159 // TODO: Better heuristic
160 std::vector<result>::iterator i = std::find_if(
161 m_results.begin()
162 , last_iterator()
163 , bind(
164 &bitwise_nand
165 , bind(&result::flags, _1)
166 , (unsigned char)result::queried
169 #ifdef TORRENT_DHT_VERBOSE_LOGGING
170 TORRENT_LOG(traversal) << "nodes left (" << this << "): " << (last_iterator() - i);
171 #endif
173 if (i == last_iterator()) break;
177 invoke(i->id, i->addr);
178 ++m_invoke_count;
179 i->flags |= result::queried;
181 catch (std::exception& e) {}
185 std::vector<traversal_algorithm::result>::iterator traversal_algorithm::last_iterator()
187 return (int)m_results.size() >= m_max_results ?
188 m_results.begin() + m_max_results
189 : m_results.end();
192 } } // namespace libtorrent::dht