3 Copyright (c) 2006, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
40 #include <libtorrent/kademlia/routing_table.hpp>
41 #include <libtorrent/kademlia/rpc_manager.hpp>
42 #include <libtorrent/kademlia/node_id.hpp>
43 #include <libtorrent/kademlia/msg.hpp>
45 #include <libtorrent/io.hpp>
46 #include <libtorrent/session_settings.hpp>
47 #include <libtorrent/assert.hpp>
49 #include <boost/cstdint.hpp>
50 #include <boost/optional.hpp>
51 #include <boost/iterator/transform_iterator.hpp>
52 #include <boost/ref.hpp>
53 #include <boost/thread/mutex.hpp>
55 #include "libtorrent/socket.hpp"
57 namespace libtorrent
{
59 namespace aux
{ struct session_impl
; }
60 struct session_status
;
64 namespace libtorrent
{ namespace dht
67 #ifdef TORRENT_DHT_VERBOSE_LOGGING
68 TORRENT_DECLARE_LOG(node
);
71 struct traversal_algorithm
;
73 // this is the entry for every peer
74 // the timestamp is there to make it possible
75 // to remove stale peers
82 // this is a group. It contains a set of group members
85 std::set
<peer_entry
> peers
;
88 inline bool operator<(peer_entry
const& lhs
, peer_entry
const& rhs
)
90 return lhs
.addr
.address() == rhs
.addr
.address()
91 ? lhs
.addr
.port() < rhs
.addr
.port()
92 : lhs
.addr
.address() < rhs
.addr
.address();
97 class announce_observer
: public observer
100 announce_observer(boost::pool
<>& allocator
101 , sha1_hash
const& info_hash
103 , entry
const& write_token
)
104 : observer(allocator
)
105 , m_info_hash(info_hash
)
106 , m_listen_port(listen_port
)
107 , m_token(write_token
)
112 m
.port
= m_listen_port
;
113 m
.info_hash
= m_info_hash
;
114 m
.write_token
= m_token
;
118 void reply(msg
const&) {}
122 sha1_hash m_info_hash
;
127 class get_peers_observer
: public observer
130 get_peers_observer(sha1_hash
const& info_hash
133 , boost::function
<void(std::vector
<tcp::endpoint
> const&, sha1_hash
const&)> f
)
134 : observer(rpc
.allocator())
135 , m_info_hash(info_hash
)
136 , m_listen_port(listen_port
)
143 m
.port
= m_listen_port
;
144 m
.info_hash
= m_info_hash
;
148 void reply(msg
const& r
)
150 observer_ptr
o(new (m_rpc
.allocator().malloc()) announce_observer(
151 m_rpc
.allocator(), m_info_hash
, m_listen_port
, r
.write_token
));
153 o
->m_in_constructor
= false;
155 m_rpc
.invoke(messages::announce_peer
, r
.addr
, o
);
156 m_fun(r
.peers
, m_info_hash
);
161 sha1_hash m_info_hash
;
164 boost::function
<void(std::vector
<tcp::endpoint
> const&, sha1_hash
const&)> m_fun
;
167 class node_impl
: boost::noncopyable
169 typedef std::map
<node_id
, torrent_entry
> table_t
;
171 node_impl(libtorrent::aux::session_impl
& ses
, boost::function
<void(msg
const&)> const& f
172 , dht_settings
const& settings
);
174 virtual ~node_impl() {}
176 void refresh(node_id
const& id
, boost::function0
<void> f
);
177 void bootstrap(std::vector
<udp::endpoint
> const& nodes
178 , boost::function0
<void> f
);
179 void find_node(node_id
const& id
, boost::function
<
180 void(std::vector
<node_entry
> const&)> f
);
181 void add_router_node(udp::endpoint router
);
183 void unreachable(udp::endpoint
const& ep
);
184 void incoming(msg
const& m
);
187 void refresh_bucket(int bucket
);
188 int bucket_size(int bucket
);
190 typedef routing_table::iterator iterator
;
192 iterator
begin() const { return m_table
.begin(); }
193 iterator
end() const { return m_table
.end(); }
195 typedef table_t::iterator data_iterator
;
197 void set_node_id(node_id
const& nid
) { m_id
= nid
; }
198 node_id
const& nid() const { return m_id
; }
200 boost::tuple
<int, int> size() const{ return m_table
.size(); }
201 size_type
num_global_nodes() const
202 { return m_table
.num_global_nodes(); }
204 data_iterator
begin_data() { return m_map
.begin(); }
205 data_iterator
end_data() { return m_map
.end(); }
206 int data_size() const { return int(m_map
.size()); }
208 #ifdef TORRENT_DHT_VERBOSE_LOGGING
209 void print_state(std::ostream
& os
) const
210 { m_table
.print_state(os
); }
213 void announce(sha1_hash
const& info_hash
, int listen_port
214 , boost::function
<void(std::vector
<tcp::endpoint
> const&
215 , sha1_hash
const&)> f
);
217 bool verify_token(msg
const& m
);
218 entry
generate_token(msg
const& m
);
220 // the returned time is the delay until connection_timeout()
221 // should be called again the next time
222 time_duration
connection_timeout();
223 time_duration
refresh_timeout();
225 // generates a new secret number used to generate write tokens
226 void new_write_key();
228 // pings the given node, and adds it to
229 // the routing table if it respons and if the
230 // bucket is not full.
231 void add_node(udp::endpoint node
);
233 void replacement_cache(bucket_t
& nodes
) const
234 { m_table
.replacement_cache(nodes
); }
236 int branch_factor() const { return m_settings
.search_branching
; }
238 void add_traversal_algorithm(traversal_algorithm
* a
)
240 mutex_t::scoped_lock
l(m_mutex
);
241 m_running_requests
.insert(a
);
244 void remove_traversal_algorithm(traversal_algorithm
* a
)
246 mutex_t::scoped_lock
l(m_mutex
);
247 m_running_requests
.erase(a
);
250 void status(libtorrent::session_status
& s
);
253 // is called when a find data request is received. Should
254 // return false if the data is not stored on this node. If
255 // the data is stored, it should be serialized into 'data'.
256 bool on_find(msg
const& m
, std::vector
<tcp::endpoint
>& peers
) const;
258 // this is called when a store request is received. The data
259 // is store-parameters and the data to be stored.
260 void on_announce(msg
const& m
, msg
& reply
);
262 dht_settings
const& m_settings
;
264 // the maximum number of peers to send in a get_peers
265 // reply. Ordinary trackers usually limit this to 50.
266 // 50 => 6 * 50 = 250 bytes + packet overhead
267 int m_max_peers_reply
;
270 typedef boost::mutex mutex_t
;
273 // this list must be destructed after the rpc manager
274 // since it might have references to it
275 std::set
<traversal_algorithm
*> m_running_requests
;
277 void incoming_request(msg
const& h
);
282 routing_table m_table
;
288 ptime m_last_tracker_tick
;
290 // secret random numbers used to create write tokens
293 libtorrent::aux::session_impl
& m_ses
;
297 } } // namespace libtorrent::dht