~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to include/libtorrent/kademlia/routing_table.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2008-07-02 10:46:21 UTC
  • Revision ID: james.westby@ubuntu.com-20080702104621-jzx3pfke9lkcxfxn
Tags: upstream-0.13.1
ImportĀ upstreamĀ versionĀ 0.13.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (c) 2006, Arvid Norberg
 
4
All rights reserved.
 
5
 
 
6
Redistribution and use in source and binary forms, with or without
 
7
modification, are permitted provided that the following conditions
 
8
are met:
 
9
 
 
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.
 
18
 
 
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.
 
30
 
 
31
*/
 
32
 
 
33
#ifndef ROUTING_TABLE_HPP
 
34
#define ROUTING_TABLE_HPP
 
35
 
 
36
#include <vector>
 
37
#include <deque>
 
38
#include <boost/cstdint.hpp>
 
39
 
 
40
#include <boost/iterator/iterator_facade.hpp>
 
41
#include <boost/iterator/iterator_categories.hpp>
 
42
#include <boost/utility.hpp>
 
43
#include <boost/tuple/tuple.hpp>
 
44
#include <boost/array.hpp>
 
45
#include <set>
 
46
 
 
47
#include <libtorrent/kademlia/logging.hpp>
 
48
 
 
49
#include <libtorrent/kademlia/node_id.hpp>
 
50
#include <libtorrent/kademlia/node_entry.hpp>
 
51
#include <libtorrent/session_settings.hpp>
 
52
#include <libtorrent/size_type.hpp>
 
53
#include <libtorrent/assert.hpp>
 
54
 
 
55
namespace libtorrent { namespace dht
 
56
{
 
57
 
 
58
using asio::ip::udp;
 
59
 
 
60
//TORRENT_DECLARE_LOG(table);
 
61
        
 
62
typedef std::vector<node_entry> bucket_t;
 
63
 
 
64
// differences in the implementation from the description in
 
65
// the paper:
 
66
//
 
67
// * The routing table tree is not allocated dynamically, there
 
68
//      are always 160 buckets.
 
69
// * Nodes are not marked as being stale, they keep a counter
 
70
//      that tells how many times in a row they have failed. When
 
71
//      a new node is to be inserted, the node that has failed
 
72
//      the most times is replaced. If none of the nodes in the
 
73
//      bucket has failed, then it is put in the replacement
 
74
//      cache (just like in the paper).
 
75
 
 
76
class routing_table;
 
77
 
 
78
namespace aux
 
79
{
 
80
 
 
81
        // Iterates over a flattened routing_table structure.
 
82
        class routing_table_iterator
 
83
        : public boost::iterator_facade<
 
84
                routing_table_iterator
 
85
                , node_entry const
 
86
                , boost::forward_traversal_tag
 
87
                >
 
88
        {
 
89
        public:
 
90
                routing_table_iterator()
 
91
                {
 
92
                }
 
93
 
 
94
        private:
 
95
                friend class libtorrent::dht::routing_table;
 
96
                friend class boost::iterator_core_access;
 
97
 
 
98
                typedef boost::array<std::pair<bucket_t, bucket_t>, 160>::const_iterator
 
99
                        bucket_iterator_t;
 
100
 
 
101
                routing_table_iterator(
 
102
                        bucket_iterator_t begin
 
103
                        , bucket_iterator_t end)
 
104
                        : m_bucket_iterator(begin)
 
105
                        , m_bucket_end(end)
 
106
                        , m_iterator(begin != end ? begin->first.begin() : bucket_t::const_iterator())
 
107
                {
 
108
                        if (m_bucket_iterator == m_bucket_end) return;
 
109
                        while (m_iterator == m_bucket_iterator->first.end())
 
110
                        {
 
111
                                if (++m_bucket_iterator == m_bucket_end)
 
112
                                        break;
 
113
                                m_iterator = m_bucket_iterator->first.begin();
 
114
                        }
 
115
                }
 
116
 
 
117
                bool equal(routing_table_iterator const& other) const
 
118
                {
 
119
                        return m_bucket_iterator == other.m_bucket_iterator
 
120
                                && (m_bucket_iterator == m_bucket_end
 
121
                                        || m_iterator == other.m_iterator);
 
122
                }
 
123
 
 
124
                void increment()
 
125
                {
 
126
                        TORRENT_ASSERT(m_bucket_iterator != m_bucket_end);
 
127
                        ++m_iterator;
 
128
                        while (m_iterator == m_bucket_iterator->first.end())
 
129
                        {
 
130
                                if (++m_bucket_iterator == m_bucket_end)
 
131
                                        break;
 
132
                                m_iterator = m_bucket_iterator->first.begin();
 
133
                        }
 
134
                }
 
135
 
 
136
                node_entry const& dereference() const
 
137
                {
 
138
                        TORRENT_ASSERT(m_bucket_iterator != m_bucket_end);
 
139
                        return *m_iterator;
 
140
                }
 
141
 
 
142
                bucket_iterator_t m_bucket_iterator;
 
143
                bucket_iterator_t m_bucket_end;
 
144
                bucket_t::const_iterator m_iterator;
 
145
        };
 
146
 
 
147
} // namespace aux
 
148
 
 
149
class routing_table
 
150
{
 
151
public:
 
152
        typedef aux::routing_table_iterator iterator;
 
153
        typedef iterator const_iterator;
 
154
 
 
155
        routing_table(node_id const& id, int bucket_size
 
156
                , dht_settings const& settings);
 
157
 
 
158
        void node_failed(node_id const& id);
 
159
        
 
160
        // adds an endpoint that will never be added to
 
161
        // the routing table
 
162
        void add_router_node(udp::endpoint router);
 
163
 
 
164
        // iterates over the router nodes added
 
165
        typedef std::set<udp::endpoint>::const_iterator router_iterator;
 
166
        router_iterator router_begin() const { return m_router_nodes.begin(); }
 
167
        router_iterator router_end() const { return m_router_nodes.end(); }
 
168
 
 
169
        // this function is called every time the node sees
 
170
        // a sign of a node being alive. This node will either
 
171
        // be inserted in the k-buckets or be moved to the top
 
172
        // of its bucket.
 
173
        bool node_seen(node_id const& id, udp::endpoint addr);
 
174
        
 
175
        // returns time when the given bucket needs another refresh.
 
176
        // if the given bucket is empty but there are nodes
 
177
        // in a bucket closer to us, or if the bucket is non-empty and
 
178
        // the time from the last activity is more than 15 minutes
 
179
        ptime next_refresh(int bucket);
 
180
 
 
181
        // fills the vector with the count nodes from our buckets that
 
182
        // are nearest to the given id.
 
183
        void find_node(node_id const& id, std::vector<node_entry>& l
 
184
                , bool include_self, int count = 0);
 
185
        
 
186
        // returns true if the given node would be placed in a bucket
 
187
        // that is not full. If the node already exists in the table
 
188
        // this function returns false
 
189
        bool need_node(node_id const& id);
 
190
        
 
191
        // this will set the given bucket's latest activity
 
192
        // to the current time
 
193
        void touch_bucket(int bucket);
 
194
        
 
195
        int bucket_size(int bucket)
 
196
        {
 
197
                TORRENT_ASSERT(bucket >= 0 && bucket < 160);
 
198
                return (int)m_buckets[bucket].first.size();
 
199
        }
 
200
        int bucket_size() const { return m_bucket_size; }
 
201
 
 
202
        iterator begin() const;
 
203
        iterator end() const;
 
204
 
 
205
        boost::tuple<int, int> size() const;
 
206
        size_type num_global_nodes() const;
 
207
        
 
208
        // returns true if there are no working nodes
 
209
        // in the routing table
 
210
        bool need_bootstrap() const;
 
211
        int num_active_buckets() const
 
212
        { return 160 - m_lowest_active_bucket + 1; }
 
213
        
 
214
        void replacement_cache(bucket_t& nodes) const;
 
215
#ifdef TORRENT_DHT_VERBOSE_LOGGING
 
216
        // used for debug and monitoring purposes. This will print out
 
217
        // the state of the routing table to the given stream
 
218
        void print_state(std::ostream& os) const;
 
219
#endif
 
220
 
 
221
private:
 
222
 
 
223
        // constant called k in paper
 
224
        int m_bucket_size;
 
225
        
 
226
        dht_settings const& m_settings;
 
227
 
 
228
        // 160 (k-bucket, replacement cache) pairs
 
229
        typedef boost::array<std::pair<bucket_t, bucket_t>, 160> table_t;
 
230
        table_t m_buckets;
 
231
        // timestamps of the last activity in each bucket
 
232
        typedef boost::array<ptime, 160> table_activity_t;
 
233
        table_activity_t m_bucket_activity;
 
234
        node_id m_id; // our own node id
 
235
        
 
236
        // this is a set of all the endpoints that have
 
237
        // been identified as router nodes. They will
 
238
        // be used in searches, but they will never
 
239
        // be added to the routing table.
 
240
        std::set<udp::endpoint> m_router_nodes;
 
241
        
 
242
        // this is the lowest bucket index with nodes in it
 
243
        int m_lowest_active_bucket;
 
244
};
 
245
 
 
246
} } // namespace libtorrent::dht
 
247
 
 
248
#endif // ROUTING_TABLE_HPP
 
249