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

« back to all changes in this revision

Viewing changes to libtorrent/src/udp_tracker_connection.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) 2003, 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
 
#include <vector>
36
 
#include <iostream>
37
 
#include <cctype>
38
 
#include <iomanip>
39
 
#include <sstream>
40
 
 
41
 
#include "zlib.h"
42
 
 
43
 
#ifdef _MSC_VER
44
 
#pragma warning(push, 1)
45
 
#endif
46
 
 
47
 
#include <boost/bind.hpp>
48
 
 
49
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
50
 
#include <boost/lexical_cast.hpp>
51
 
using boost::lexical_cast;
52
 
#endif
53
 
 
54
 
#ifdef _MSC_VER
55
 
#pragma warning(pop)
56
 
#endif
57
 
 
58
 
#include "libtorrent/tracker_manager.hpp"
59
 
#include "libtorrent/parse_url.hpp"
60
 
#include "libtorrent/udp_tracker_connection.hpp"
61
 
#include "libtorrent/io.hpp"
62
 
#include "libtorrent/escape_string.hpp"
63
 
 
64
 
namespace
65
 
{
66
 
        enum
67
 
        {
68
 
                udp_connection_retries = 4,
69
 
                udp_announce_retries = 15,
70
 
                udp_connect_timeout = 15,
71
 
                udp_announce_timeout = 10
72
 
        };
73
 
}
74
 
 
75
 
using boost::bind;
76
 
 
77
 
namespace libtorrent
78
 
{
79
 
 
80
 
        udp_tracker_connection::udp_tracker_connection(
81
 
                io_service& ios
82
 
                , connection_queue& cc
83
 
                , tracker_manager& man
84
 
                , tracker_request const& req
85
 
                , address bind_infc
86
 
                , boost::weak_ptr<request_callback> c
87
 
                , session_settings const& stn
88
 
                , proxy_settings const& proxy)
89
 
                : tracker_connection(man, req, ios, bind_infc, c)
90
 
                , m_man(man)
91
 
                , m_name_lookup(ios)
92
 
                , m_socket(ios, boost::bind(&udp_tracker_connection::on_receive, self(), _1, _2, _3, _4), cc)
93
 
                , m_transaction_id(0)
94
 
                , m_connection_id(0)
95
 
                , m_settings(stn)
96
 
                , m_attempts(0)
97
 
                , m_state(action_error)
98
 
        {
99
 
                m_socket.set_proxy_settings(proxy);
100
 
        }
101
 
 
102
 
        void udp_tracker_connection::start()
103
 
        {
104
 
                std::string hostname;
105
 
                int port;
106
 
                char const* error;
107
 
 
108
 
                using boost::tuples::ignore;
109
 
                boost::tie(ignore, ignore, hostname, port, ignore, error)
110
 
                        = parse_url_components(tracker_req().url);
111
 
 
112
 
                if (error)
113
 
                {
114
 
                        fail(-1, error);
115
 
                        return;
116
 
                }
117
 
                
118
 
                udp::resolver::query q(hostname, to_string(port).elems);
119
 
                m_name_lookup.async_resolve(q
120
 
                        , boost::bind(
121
 
                        &udp_tracker_connection::name_lookup, self(), _1, _2));
122
 
                set_timeout(tracker_req().event == tracker_request::stopped
123
 
                        ? m_settings.stop_tracker_timeout
124
 
                        : m_settings.tracker_completion_timeout
125
 
                        , m_settings.tracker_receive_timeout);
126
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
127
 
                boost::shared_ptr<request_callback> cb = requester();
128
 
                if (cb) cb->debug_log(("*** UDP_TRACKER [ initiating name lookup: " + hostname + " ]").c_str());
129
 
#endif
130
 
        }
131
 
 
132
 
        void udp_tracker_connection::name_lookup(error_code const& error
133
 
                , udp::resolver::iterator i)
134
 
        {
135
 
                if (error == asio::error::operation_aborted) return;
136
 
                if (error || i == udp::resolver::iterator())
137
 
                {
138
 
                        fail(-1, error.message().c_str());
139
 
                        return;
140
 
                }
141
 
 
142
 
                boost::shared_ptr<request_callback> cb = requester();
143
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
144
 
                if (cb) cb->debug_log("*** UDP_TRACKER [ name lookup successful ]");
145
 
#endif
146
 
                restart_read_timeout();
147
 
                
148
 
                // look for an address that has the same kind as the one
149
 
                // we're listening on. To make sure the tracker get our
150
 
                // correct listening address.
151
 
                udp::resolver::iterator target = i;
152
 
                udp::resolver::iterator end;
153
 
                udp::endpoint target_address = *i;
154
 
                for (; target != end && target->endpoint().address().is_v4()
155
 
                        != bind_interface().is_v4(); ++target);
156
 
                if (target == end)
157
 
                {
158
 
                        TORRENT_ASSERT(target_address.address().is_v4() != bind_interface().is_v4());
159
 
                        if (cb)
160
 
                        {
161
 
                                std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
162
 
                                std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
163
 
                                cb->tracker_warning(tracker_req(), "the tracker only resolves to an "
164
 
                                        + tracker_address_type + " address, and you're listening on an "
165
 
                                        + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
166
 
                        }
167
 
                }
168
 
                else
169
 
                {
170
 
                        target_address = *target;
171
 
                }
172
 
                
173
 
                if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
174
 
                m_target = target_address;
175
 
                error_code ec;
176
 
                m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
177
 
                if (ec)
178
 
                {
179
 
                        fail(-1, ec.message().c_str());
180
 
                        return;
181
 
                }
182
 
                send_udp_connect();
183
 
        }
184
 
 
185
 
        void udp_tracker_connection::on_timeout()
186
 
        {
187
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
188
 
                boost::shared_ptr<request_callback> cb = requester();
189
 
                if (cb) cb->debug_log("*** UDP_TRACKER [ timed out ]");
190
 
#endif
191
 
                m_socket.close();
192
 
                m_name_lookup.cancel();
193
 
                fail_timeout();
194
 
        }
195
 
 
196
 
        void udp_tracker_connection::close()
197
 
        {
198
 
                error_code ec;
199
 
                m_socket.close();
200
 
                m_name_lookup.cancel();
201
 
                tracker_connection::close();
202
 
        }
203
 
 
204
 
        void udp_tracker_connection::on_receive(error_code const& e
205
 
                , udp::endpoint const& ep, char const* buf, int size)
206
 
        {
207
 
                // ignore resposes before we've sent any requests
208
 
                if (m_state == action_error) return;
209
 
 
210
 
                if (!m_socket.is_open()) return; // the operation was aborted
211
 
 
212
 
                // ignore packet not sent from the tracker
213
 
                if (m_target != ep) return;
214
 
                
215
 
                if (e) fail(-1, e.message().c_str());
216
 
 
217
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
218
 
                boost::shared_ptr<request_callback> cb = requester();
219
 
                if (cb)
220
 
                {
221
 
                        std::stringstream msg;
222
 
                        msg << "<== UDP_TRACKER_PACKET [ size: " << size << " ]";
223
 
                        cb->debug_log(msg.str());
224
 
                }
225
 
#endif
226
 
 
227
 
                // ignore packets smaller than 8 bytes
228
 
                if (size < 8) return;
229
 
 
230
 
                restart_read_timeout();
231
 
 
232
 
                const char* ptr = buf;
233
 
                int action = detail::read_int32(ptr);
234
 
                int transaction = detail::read_int32(ptr);
235
 
 
236
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
237
 
                if (cb)
238
 
                {
239
 
                        std::stringstream msg;
240
 
                        msg << "*** UDP_TRACKER_PACKET [ acton: " << action << " ]";
241
 
                        cb->debug_log(msg.str());
242
 
                }
243
 
#endif
244
 
 
245
 
                // ignore packets with incorrect transaction id
246
 
                if (m_transaction_id != transaction) return;
247
 
 
248
 
                if (action == action_error)
249
 
                {
250
 
                        fail(-1, std::string(ptr, size - 8).c_str());
251
 
                        return;
252
 
                }
253
 
 
254
 
                // ignore packets that's not a response to our message
255
 
                if (action != m_state) return;
256
 
 
257
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
258
 
                if (cb)
259
 
                {
260
 
                        std::stringstream msg;
261
 
                        msg << "*** UDP_TRACKER_RESPONSE [ cid: " << m_connection_id << " ]";
262
 
                        cb->debug_log(msg.str());
263
 
                }
264
 
#endif
265
 
 
266
 
                switch (m_state)
267
 
                {
268
 
                        case action_connect:
269
 
                                on_connect_response(buf, size);
270
 
                                break;
271
 
                        case action_announce:
272
 
                                on_announce_response(buf, size);
273
 
                                break;
274
 
                        case action_scrape:
275
 
                                on_scrape_response(buf, size);
276
 
                                break;
277
 
                        default: break;
278
 
                }
279
 
        }
280
 
        
281
 
        void udp_tracker_connection::on_connect_response(char const* buf, int size)
282
 
        {
283
 
                // ignore packets smaller than 16 bytes
284
 
                if (size < 16) return;
285
 
 
286
 
                restart_read_timeout();
287
 
                buf += 8; // skip header
288
 
 
289
 
                // reset transaction
290
 
                m_transaction_id = 0;
291
 
                m_attempts = 0;
292
 
                m_connection_id = detail::read_int64(buf);
293
 
 
294
 
                if (tracker_req().kind == tracker_request::announce_request)
295
 
                        send_udp_announce();
296
 
                else if (tracker_req().kind == tracker_request::scrape_request)
297
 
                        send_udp_scrape();
298
 
        }
299
 
 
300
 
        void udp_tracker_connection::send_udp_connect()
301
 
        {
302
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
303
 
                boost::shared_ptr<request_callback> cb = requester();
304
 
                if (cb)
305
 
                {
306
 
                        cb->debug_log("==> UDP_TRACKER_CONNECT ["
307
 
                                + lexical_cast<std::string>(tracker_req().info_hash) + "]");
308
 
                }
309
 
#endif
310
 
                if (!m_socket.is_open()) return; // the operation was aborted
311
 
 
312
 
                char buf[16];
313
 
                char* ptr = buf;
314
 
 
315
 
                if (m_transaction_id == 0)
316
 
                        m_transaction_id = std::rand() ^ (std::rand() << 16);
317
 
 
318
 
                detail::write_uint32(0x417, ptr);
319
 
                detail::write_uint32(0x27101980, ptr); // connection_id
320
 
                detail::write_int32(action_connect, ptr); // action (connect)
321
 
                detail::write_int32(m_transaction_id, ptr); // transaction_id
322
 
                TORRENT_ASSERT(ptr - buf == sizeof(buf));
323
 
 
324
 
                error_code ec;
325
 
                m_socket.send(m_target, buf, 16, ec);
326
 
                m_state = action_connect;
327
 
                ++m_attempts;
328
 
                if (ec)
329
 
                {
330
 
                        fail(-1, ec.message().c_str());
331
 
                        return;
332
 
                }
333
 
        }
334
 
 
335
 
        void udp_tracker_connection::send_udp_scrape()
336
 
        {
337
 
                if (m_transaction_id == 0)
338
 
                        m_transaction_id = std::rand() ^ (std::rand() << 16);
339
 
 
340
 
                if (!m_socket.is_open()) return; // the operation was aborted
341
 
 
342
 
                char buf[8 + 4 + 4 + 20];
343
 
                char* out = buf;
344
 
 
345
 
                detail::write_int64(m_connection_id, out); // connection_id
346
 
                detail::write_int32(action_scrape, out); // action (scrape)
347
 
                detail::write_int32(m_transaction_id, out); // transaction_id
348
 
                // info_hash
349
 
                std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
350
 
                out += 20;
351
 
                TORRENT_ASSERT(out - buf == sizeof(buf));
352
 
 
353
 
                error_code ec;
354
 
                m_socket.send(m_target, buf, sizeof(buf), ec);
355
 
                m_state = action_scrape;
356
 
                ++m_attempts;
357
 
                if (ec)
358
 
                {
359
 
                        fail(-1, ec.message().c_str());
360
 
                        return;
361
 
                }
362
 
        }
363
 
 
364
 
        void udp_tracker_connection::on_announce_response(char const* buf, int size)
365
 
        {
366
 
                if (size < 20) return;
367
 
 
368
 
                restart_read_timeout();
369
 
 
370
 
                buf += 8; // skip header
371
 
                restart_read_timeout();
372
 
                int interval = detail::read_int32(buf);
373
 
                int incomplete = detail::read_int32(buf);
374
 
                int complete = detail::read_int32(buf);
375
 
                int num_peers = (size - 20) / 6;
376
 
                if ((size - 20) % 6 != 0)
377
 
                {
378
 
                        fail(-1, "invalid udp tracker response length");
379
 
                        return;
380
 
                }
381
 
 
382
 
                boost::shared_ptr<request_callback> cb = requester();
383
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
384
 
                if (cb)
385
 
                {
386
 
                        cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
387
 
                }
388
 
#endif
389
 
 
390
 
                if (!cb)
391
 
                {
392
 
                        m_man.remove_request(this);
393
 
                        return;
394
 
                }
395
 
 
396
 
                std::vector<peer_entry> peer_list;
397
 
                for (int i = 0; i < num_peers; ++i)
398
 
                {
399
 
                        // TODO: don't use a string here
400
 
                        peer_entry e;
401
 
                        std::stringstream s;
402
 
                        s << (int)detail::read_uint8(buf) << ".";
403
 
                        s << (int)detail::read_uint8(buf) << ".";
404
 
                        s << (int)detail::read_uint8(buf) << ".";
405
 
                        s << (int)detail::read_uint8(buf);
406
 
                        e.ip = s.str();
407
 
                        e.port = detail::read_uint16(buf);
408
 
                        e.pid.clear();
409
 
                        peer_list.push_back(e);
410
 
                }
411
 
 
412
 
                cb->tracker_response(tracker_req(), peer_list, interval
413
 
                        , complete, incomplete, address());
414
 
 
415
 
                m_man.remove_request(this);
416
 
                close();
417
 
        }
418
 
 
419
 
        void udp_tracker_connection::on_scrape_response(char const* buf, int size)
420
 
        {
421
 
                buf += 8; // skip header
422
 
 
423
 
                restart_read_timeout();
424
 
                int action = detail::read_int32(buf);
425
 
                int transaction = detail::read_int32(buf);
426
 
 
427
 
                if (transaction != m_transaction_id)
428
 
                {
429
 
                        fail(-1, "incorrect transaction id");
430
 
                        return;
431
 
                }
432
 
 
433
 
                if (action == action_error)
434
 
                {
435
 
                        fail(-1, std::string(buf, size - 8).c_str());
436
 
                        return;
437
 
                }
438
 
 
439
 
                if (action != action_scrape)
440
 
                {
441
 
                        fail(-1, "invalid action in announce response");
442
 
                        return;
443
 
                }
444
 
 
445
 
                if (size < 20)
446
 
                {
447
 
                        fail(-1, "got a message with size < 20");
448
 
                        return;
449
 
                }
450
 
 
451
 
                int complete = detail::read_int32(buf);
452
 
                int downloaded = detail::read_int32(buf);
453
 
                int incomplete = detail::read_int32(buf);
454
 
 
455
 
                boost::shared_ptr<request_callback> cb = requester();
456
 
                if (!cb)
457
 
                {
458
 
                        close();
459
 
                        return;
460
 
                }
461
 
                
462
 
                cb->tracker_scrape_response(tracker_req()
463
 
                        , complete, incomplete, downloaded);
464
 
 
465
 
                m_man.remove_request(this);
466
 
                close();
467
 
        }
468
 
 
469
 
        void udp_tracker_connection::send_udp_announce()
470
 
        {
471
 
                if (m_transaction_id == 0)
472
 
                        m_transaction_id = std::rand() ^ (std::rand() << 16);
473
 
 
474
 
                if (!m_socket.is_open()) return; // the operation was aborted
475
 
 
476
 
                char buf[8 + 4 + 4 + 20 + 20 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 2 + 2];
477
 
                char* out = buf;
478
 
 
479
 
                tracker_request const& req = tracker_req();
480
 
 
481
 
                detail::write_int64(m_connection_id, out); // connection_id
482
 
                detail::write_int32(action_announce, out); // action (announce)
483
 
                detail::write_int32(m_transaction_id, out); // transaction_id
484
 
                std::copy(req.info_hash.begin(), req.info_hash.end(), out); // info_hash
485
 
                out += 20;
486
 
                std::copy(req.pid.begin(), req.pid.end(), out); // peer_id
487
 
                out += 20;
488
 
                detail::write_int64(req.downloaded, out); // downloaded
489
 
                detail::write_int64(req.left, out); // left
490
 
                detail::write_int64(req.uploaded, out); // uploaded
491
 
                detail::write_int32(req.event, out); // event
492
 
                // ip address
493
 
                if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4())
494
 
                        detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out);
495
 
                else
496
 
                        detail::write_int32(0, out);
497
 
                detail::write_int32(req.key, out); // key
498
 
                detail::write_int32(req.num_want, out); // num_want
499
 
                detail::write_uint16(req.listen_port, out); // port
500
 
                detail::write_uint16(0, out); // extensions
501
 
 
502
 
                TORRENT_ASSERT(out - buf == sizeof(buf));
503
 
 
504
 
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
505
 
                boost::shared_ptr<request_callback> cb = requester();
506
 
                if (cb)
507
 
                {
508
 
                        cb->debug_log("==> UDP_TRACKER_ANNOUNCE ["
509
 
                                + lexical_cast<std::string>(req.info_hash) + "]");
510
 
                }
511
 
#endif
512
 
 
513
 
                error_code ec;
514
 
                m_socket.send(m_target, buf, sizeof(buf), ec);
515
 
                m_state = action_announce;
516
 
                ++m_attempts;
517
 
                if (ec)
518
 
                {
519
 
                        fail(-1, ec.message().c_str());
520
 
                        return;
521
 
                }
522
 
        }
523
 
 
524
 
}
525