~cmiller/ubuntu/quantal/deluge/fix-parameter-move-storage

« back to all changes in this revision

Viewing changes to libtorrent/src/ut_pex.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2009-11-13 02:39:45 UTC
  • mfrom: (4.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091113023945-te1bybo2912ejzuc
Tags: 1.2.0~rc3-4
* debian/control: bump build-dep on python-setuptools to (>= 0.6c9).
* debian/patches:
  - 25_r5921_fastresume_files.patch
    new, should fix problems with fresh configs;
  - 30_r5931_ipc_lockfile.patch:
    new, should fix an issue where Deluge will fail to start if there is a
    stale ipc lockfile. (Closes: #555849)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
Copyright (c) 2006, MassaRoddel, 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
 
#include "libtorrent/pch.hpp"
34
 
 
35
 
#ifdef _MSC_VER
36
 
#pragma warning(push, 1)
37
 
#endif
38
 
 
39
 
#include <boost/shared_ptr.hpp>
40
 
 
41
 
#ifdef _MSC_VER
42
 
#pragma warning(pop)
43
 
#endif
44
 
 
45
 
#include "libtorrent/peer_connection.hpp"
46
 
#include "libtorrent/bt_peer_connection.hpp"
47
 
#include "libtorrent/bencode.hpp"
48
 
#include "libtorrent/torrent.hpp"
49
 
#include "libtorrent/extensions.hpp"
50
 
 
51
 
#include "libtorrent/extensions/ut_pex.hpp"
52
 
 
53
 
namespace libtorrent { namespace
54
 
{
55
 
        const char extension_name[] = "ut_pex";
56
 
 
57
 
        enum
58
 
        {
59
 
                extension_index = 1,
60
 
                max_peer_entries = 100
61
 
        };
62
 
 
63
 
        bool send_peer(peer_connection const& p)
64
 
        {
65
 
                // don't send out peers that we haven't connected to
66
 
                // (that have connected to us)
67
 
                if (!p.is_local()) return false;
68
 
                // don't send out peers that we haven't successfully connected to
69
 
                if (p.is_connecting()) return false;
70
 
                return true;
71
 
        }
72
 
 
73
 
        struct ut_pex_plugin: torrent_plugin
74
 
        {
75
 
                ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}
76
 
        
77
 
                virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);
78
 
 
79
 
                std::vector<char>& get_ut_pex_msg()
80
 
                {
81
 
                        return m_ut_pex_msg;
82
 
                }
83
 
 
84
 
                // the second tick of the torrent
85
 
                // each minute the new lists of "added" + "added.f" and "dropped"
86
 
                // are calculated here and the pex message is created
87
 
                // each peer connection will use this message
88
 
                // max_peer_entries limits the packet size
89
 
                virtual void tick()
90
 
                {
91
 
                        if (++m_1_minute < 60) return;
92
 
 
93
 
                        m_1_minute = 0;
94
 
 
95
 
                        entry pex;
96
 
                        std::string& pla = pex["added"].string();
97
 
                        std::string& pld = pex["dropped"].string();
98
 
                        std::string& plf = pex["added.f"].string();
99
 
                        std::string& pla6 = pex["added6"].string();
100
 
                        std::string& pld6 = pex["dropped6"].string();
101
 
                        std::string& plf6 = pex["added6.f"].string();
102
 
                        std::back_insert_iterator<std::string> pla_out(pla);
103
 
                        std::back_insert_iterator<std::string> pld_out(pld);
104
 
                        std::back_insert_iterator<std::string> plf_out(plf);
105
 
                        std::back_insert_iterator<std::string> pla6_out(pla6);
106
 
                        std::back_insert_iterator<std::string> pld6_out(pld6);
107
 
                        std::back_insert_iterator<std::string> plf6_out(plf6);
108
 
 
109
 
                        std::set<tcp::endpoint> dropped;
110
 
                        m_old_peers.swap(dropped);
111
 
 
112
 
                        int num_added = 0;
113
 
                        for (torrent::peer_iterator i = m_torrent.begin()
114
 
                                , end(m_torrent.end()); i != end; ++i)
115
 
                        {
116
 
                                peer_connection* peer = *i;
117
 
                                if (!send_peer(*peer)) continue;
118
 
 
119
 
                                tcp::endpoint const& remote = peer->remote();
120
 
                                m_old_peers.insert(remote);
121
 
 
122
 
                                std::set<tcp::endpoint>::iterator di = dropped.find(remote);
123
 
                                if (di == dropped.end())
124
 
                                {
125
 
                                        // don't write too big of a package
126
 
                                        if (num_added >= max_peer_entries) break;
127
 
 
128
 
                                        // only send proper bittorrent peers
129
 
                                        bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
130
 
                                        if (!p) continue;
131
 
 
132
 
                                        // no supported flags to set yet
133
 
                                        // 0x01 - peer supports encryption
134
 
                                        // 0x02 - peer is a seed
135
 
                                        int flags = p->is_seed() ? 2 : 0;
136
 
#ifndef TORRENT_DISABLE_ENCRYPTION
137
 
                                        flags |= p->supports_encryption() ? 1 : 0;
138
 
#endif
139
 
                                        // i->first was added since the last time
140
 
                                        if (remote.address().is_v4())
141
 
                                        {
142
 
                                                detail::write_endpoint(remote, pla_out);
143
 
                                                detail::write_uint8(flags, plf_out);
144
 
                                        }
145
 
                                        else
146
 
                                        {
147
 
                                                detail::write_endpoint(remote, pla6_out);
148
 
                                                detail::write_uint8(flags, plf6_out);
149
 
                                        }
150
 
                                        ++num_added;
151
 
                                }
152
 
                                else
153
 
                                {
154
 
                                        // this was in the previous message
155
 
                                        // so, it wasn't dropped
156
 
                                        dropped.erase(di);
157
 
                                }
158
 
                        }
159
 
 
160
 
                        for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
161
 
                                , end(dropped.end()); i != end; ++i)
162
 
                        {       
163
 
                                if (i->address().is_v4())
164
 
                                        detail::write_endpoint(*i, pld_out);
165
 
                                else
166
 
                                        detail::write_endpoint(*i, pld6_out);
167
 
                        }
168
 
 
169
 
                        m_ut_pex_msg.clear();
170
 
                        bencode(std::back_inserter(m_ut_pex_msg), pex);
171
 
                }
172
 
 
173
 
        private:
174
 
                torrent& m_torrent;
175
 
 
176
 
                std::set<tcp::endpoint> m_old_peers;
177
 
                int m_1_minute;
178
 
                std::vector<char> m_ut_pex_msg;
179
 
        };
180
 
 
181
 
 
182
 
        struct ut_pex_peer_plugin : peer_plugin
183
 
        {       
184
 
                ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
185
 
                        : m_torrent(t)
186
 
                        , m_pc(pc)
187
 
                        , m_tp(tp)
188
 
                        , m_1_minute(55)
189
 
                        , m_message_index(0)
190
 
                        , m_first_time(true)
191
 
                {}
192
 
 
193
 
                virtual void add_handshake(entry& h)
194
 
                {
195
 
                        entry& messages = h["m"];
196
 
                        messages[extension_name] = extension_index;
197
 
                }
198
 
 
199
 
                virtual bool on_extension_handshake(lazy_entry const& h)
200
 
                {
201
 
                        m_message_index = 0;
202
 
                        if (h.type() != lazy_entry::dict_t) return false;
203
 
                        lazy_entry const* messages = h.dict_find("m");
204
 
                        if (!messages || messages->type() != lazy_entry::dict_t) return false;
205
 
 
206
 
                        int index = messages->dict_find_int_value(extension_name, -1);
207
 
                        if (index == -1) return false;
208
 
                        m_message_index = index;
209
 
                        return true;
210
 
                }
211
 
 
212
 
                virtual bool on_extended(int length, int msg, buffer::const_interval body)
213
 
                {
214
 
                        if (msg != extension_index) return false;
215
 
                        if (m_message_index == 0) return false;
216
 
 
217
 
                        if (length > 500 * 1024)
218
 
                        {
219
 
                                m_pc.disconnect("peer exchange message larger than 500 kB", 2);
220
 
                                return true;
221
 
                        }
222
 
 
223
 
                        if (body.left() < length) return true;
224
 
 
225
 
                        lazy_entry pex_msg;
226
 
                        int ret = lazy_bdecode(body.begin, body.end, pex_msg);
227
 
                        if (pex_msg.type() != lazy_entry::dict_t)
228
 
                        {
229
 
                                m_pc.disconnect("invalid bencoding in ut_metadata message", 2);
230
 
                                return true;
231
 
                        }
232
 
 
233
 
                        lazy_entry const* p = pex_msg.dict_find("added");
234
 
                        lazy_entry const* pf = pex_msg.dict_find("added.f");
235
 
 
236
 
                        if (p != 0
237
 
                                && pf != 0
238
 
                                && p->type() == lazy_entry::string_t
239
 
                                && pf->type() == lazy_entry::string_t
240
 
                                && pf->string_length() == p->string_length() / 6)
241
 
                        {
242
 
                                int num_peers = pf->string_length();
243
 
                                char const* in = p->string_ptr();
244
 
                                char const* fin = pf->string_ptr();
245
 
 
246
 
                                peer_id pid(0);
247
 
                                policy& p = m_torrent.get_policy();
248
 
                                for (int i = 0; i < num_peers; ++i)
249
 
                                {
250
 
                                        tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
251
 
                                        char flags = *fin++;
252
 
                                        p.peer_from_tracker(adr, pid, peer_info::pex, flags);
253
 
                                } 
254
 
                        }
255
 
 
256
 
                        lazy_entry const* p6 = pex_msg.dict_find("added6");
257
 
                        lazy_entry const* p6f = pex_msg.dict_find("added6.f");
258
 
                        if (p6 != 0
259
 
                                && p6f != 0
260
 
                                && p6->type() == lazy_entry::string_t
261
 
                                && p6f->type() == lazy_entry::string_t
262
 
                                && p6f->string_length() == p6->string_length() / 18)
263
 
                        {
264
 
                                int num_peers = p6f->string_length();
265
 
                                char const* in = p6->string_ptr();
266
 
                                char const* fin = p6f->string_ptr();
267
 
 
268
 
                                peer_id pid(0);
269
 
                                policy& p = m_torrent.get_policy();
270
 
                                for (int i = 0; i < num_peers; ++i)
271
 
                                {
272
 
                                        tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
273
 
                                        char flags = *fin++;
274
 
                                        p.peer_from_tracker(adr, pid, peer_info::pex, flags);
275
 
                                } 
276
 
                        }
277
 
                        return true;
278
 
                }
279
 
 
280
 
                // the peers second tick
281
 
                // every minute we send a pex message
282
 
                virtual void tick()
283
 
                {
284
 
                        if (!m_message_index) return;   // no handshake yet
285
 
                        if (++m_1_minute <= 60) return;
286
 
 
287
 
                        if (m_first_time)
288
 
                        {
289
 
                                send_ut_peer_list();
290
 
                                m_first_time = false;
291
 
                        }
292
 
                        else
293
 
                        {
294
 
                                send_ut_peer_diff();
295
 
                        }
296
 
                        m_1_minute = 0;
297
 
                }
298
 
 
299
 
        private:
300
 
 
301
 
                void send_ut_peer_diff()
302
 
                {
303
 
                        std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();
304
 
 
305
 
                        buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
306
 
 
307
 
                        detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
308
 
                        detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
309
 
                        detail::write_uint8(m_message_index, i.begin);
310
 
                        std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
311
 
                        i.begin += pex_msg.size();
312
 
 
313
 
                        TORRENT_ASSERT(i.begin == i.end);
314
 
                        m_pc.setup_send();
315
 
                }
316
 
 
317
 
                void send_ut_peer_list()
318
 
                {
319
 
                        entry pex;
320
 
                        // leave the dropped string empty
321
 
                        pex["dropped"].string();
322
 
                        std::string& pla = pex["added"].string();
323
 
                        std::string& plf = pex["added.f"].string();
324
 
                        pex["dropped6"].string();
325
 
                        std::string& pla6 = pex["added6"].string();
326
 
                        std::string& plf6 = pex["added6.f"].string();
327
 
                        std::back_insert_iterator<std::string> pla_out(pla);
328
 
                        std::back_insert_iterator<std::string> plf_out(plf);
329
 
                        std::back_insert_iterator<std::string> pla6_out(pla6);
330
 
                        std::back_insert_iterator<std::string> plf6_out(plf6);
331
 
 
332
 
                        int num_added = 0;
333
 
                        for (torrent::peer_iterator i = m_torrent.begin()
334
 
                                , end(m_torrent.end()); i != end; ++i)
335
 
                        {
336
 
                                peer_connection* peer = *i;
337
 
                                if (!send_peer(*peer)) continue;
338
 
 
339
 
                                // don't write too big of a package
340
 
                                if (num_added >= max_peer_entries) break;
341
 
 
342
 
                                // only send proper bittorrent peers
343
 
                                bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
344
 
                                if (!p) continue;
345
 
 
346
 
                                // no supported flags to set yet
347
 
                                // 0x01 - peer supports encryption
348
 
                                // 0x02 - peer is a seed
349
 
                                int flags = p->is_seed() ? 2 : 0;
350
 
#ifndef TORRENT_DISABLE_ENCRYPTION
351
 
                                flags |= p->supports_encryption() ? 1 : 0;
352
 
#endif
353
 
                                tcp::endpoint const& remote = peer->remote();
354
 
                                // i->first was added since the last time
355
 
                                if (remote.address().is_v4())
356
 
                                {
357
 
                                        detail::write_endpoint(remote, pla_out);
358
 
                                        detail::write_uint8(flags, plf_out);
359
 
                                }
360
 
                                else
361
 
                                {
362
 
                                        detail::write_endpoint(remote, pla6_out);
363
 
                                        detail::write_uint8(flags, plf6_out);
364
 
                                }
365
 
                                ++num_added;
366
 
                        }
367
 
                        std::vector<char> pex_msg;
368
 
                        bencode(std::back_inserter(pex_msg), pex);
369
 
 
370
 
                        buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
371
 
 
372
 
                        detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
373
 
                        detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
374
 
                        detail::write_uint8(m_message_index, i.begin);
375
 
                        std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
376
 
                        i.begin += pex_msg.size();
377
 
 
378
 
                        TORRENT_ASSERT(i.begin == i.end);
379
 
                        m_pc.setup_send();
380
 
                }
381
 
 
382
 
                torrent& m_torrent;
383
 
                peer_connection& m_pc;
384
 
                ut_pex_plugin& m_tp;
385
 
                int m_1_minute;
386
 
                int m_message_index;
387
 
 
388
 
                // this is initialized to true, and set to
389
 
                // false after the first pex message has been sent.
390
 
                // it is used to know if a diff message or a full
391
 
                // message should be sent.
392
 
                bool m_first_time;
393
 
        };
394
 
 
395
 
        boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
396
 
        {
397
 
                bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
398
 
                if (!c) return boost::shared_ptr<peer_plugin>();
399
 
                return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
400
 
                        , *pc, *this));
401
 
        }
402
 
}}
403
 
 
404
 
namespace libtorrent
405
 
{
406
 
 
407
 
        boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
408
 
        {
409
 
                if (t->torrent_file().priv())
410
 
                {
411
 
                        return boost::shared_ptr<torrent_plugin>();
412
 
                }
413
 
                return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
414
 
        }
415
 
 
416
 
}
417
 
 
418