file_progress fix
[libtorrent.git] / src / udp_tracker_connection.cpp
blobe19d5696da50d72e0c4248b25f386db0dcc4ab6d
1 /*
3 Copyright (c) 2003, Arvid Norberg
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 <vector>
36 #include <iostream>
37 #include <cctype>
38 #include <iomanip>
39 #include <sstream>
41 #include "zlib.h"
43 #ifdef _MSC_VER
44 #pragma warning(push, 1)
45 #endif
47 #include <boost/bind.hpp>
48 #include <boost/lexical_cast.hpp>
50 #ifdef _MSC_VER
51 #pragma warning(pop)
52 #endif
54 #include "libtorrent/tracker_manager.hpp"
55 #include "libtorrent/parse_url.hpp"
56 #include "libtorrent/udp_tracker_connection.hpp"
57 #include "libtorrent/io.hpp"
59 namespace
61 enum
63 udp_connection_retries = 4,
64 udp_announce_retries = 15,
65 udp_connect_timeout = 15,
66 udp_announce_timeout = 10
70 using boost::bind;
71 using boost::lexical_cast;
73 namespace libtorrent
76 udp_tracker_connection::udp_tracker_connection(
77 io_service& ios
78 , connection_queue& cc
79 , tracker_manager& man
80 , tracker_request const& req
81 , address bind_infc
82 , boost::weak_ptr<request_callback> c
83 , session_settings const& stn
84 , proxy_settings const& proxy)
85 : tracker_connection(man, req, ios, bind_infc, c)
86 , m_man(man)
87 , m_name_lookup(ios)
88 , m_socket(ios, boost::bind(&udp_tracker_connection::on_receive, self(), _1, _2, _3, _4), cc)
89 , m_transaction_id(0)
90 , m_connection_id(0)
91 , m_settings(stn)
92 , m_attempts(0)
93 , m_state(action_error)
95 m_socket.set_proxy_settings(proxy);
97 std::string hostname;
98 int port;
99 char const* error;
101 using boost::tuples::ignore;
102 boost::tie(ignore, ignore, hostname, port, ignore, error)
103 = parse_url_components(req.url);
105 if (error)
107 fail(-1, error);
108 return;
111 udp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
112 m_name_lookup.async_resolve(q
113 , boost::bind(
114 &udp_tracker_connection::name_lookup, self(), _1, _2));
115 set_timeout(req.event == tracker_request::stopped
116 ? m_settings.stop_tracker_timeout
117 : m_settings.tracker_completion_timeout
118 , m_settings.tracker_receive_timeout);
119 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
120 boost::shared_ptr<request_callback> cb = requester();
121 if (cb) cb->debug_log(("*** UDP_TRACKER [ initiating name lookup: " + hostname + " ]").c_str());
122 #endif
125 void udp_tracker_connection::name_lookup(error_code const& error
126 , udp::resolver::iterator i)
128 if (error == asio::error::operation_aborted) return;
129 if (error || i == udp::resolver::iterator())
131 fail(-1, error.message().c_str());
132 return;
135 boost::shared_ptr<request_callback> cb = requester();
136 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
137 if (cb) cb->debug_log("*** UDP_TRACKER [ name lookup successful ]");
138 #endif
139 restart_read_timeout();
141 // look for an address that has the same kind as the one
142 // we're listening on. To make sure the tracker get our
143 // correct listening address.
144 udp::resolver::iterator target = i;
145 udp::resolver::iterator end;
146 udp::endpoint target_address = *i;
147 for (; target != end && target->endpoint().address().is_v4()
148 != bind_interface().is_v4(); ++target);
149 if (target == end)
151 TORRENT_ASSERT(target_address.address().is_v4() != bind_interface().is_v4());
152 if (cb)
154 std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
155 std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
156 cb->tracker_warning(tracker_req(), "the tracker only resolves to an "
157 + tracker_address_type + " address, and you're listening on an "
158 + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
161 else
163 target_address = *target;
166 if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
167 m_target = target_address;
168 error_code ec;
169 m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
170 if (ec)
172 fail(-1, ec.message().c_str());
173 return;
175 send_udp_connect();
178 void udp_tracker_connection::on_timeout()
180 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
181 boost::shared_ptr<request_callback> cb = requester();
182 if (cb) cb->debug_log("*** UDP_TRACKER [ timed out ]");
183 #endif
184 m_socket.close();
185 m_name_lookup.cancel();
186 fail_timeout();
189 void udp_tracker_connection::close()
191 error_code ec;
192 m_socket.close();
193 m_name_lookup.cancel();
194 tracker_connection::close();
197 void udp_tracker_connection::on_receive(error_code const& e
198 , udp::endpoint const& ep, char const* buf, int size)
200 // ignore resposes before we've sent any requests
201 if (m_state == action_error) return;
203 if (!m_socket.is_open()) return; // the operation was aborted
205 // ignore packet not sent from the tracker
206 if (m_target != ep) return;
208 if (e) fail(-1, e.message().c_str());
210 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
211 boost::shared_ptr<request_callback> cb = requester();
212 if (cb)
214 std::stringstream msg;
215 msg << "<== UDP_TRACKER_PACKET [ size: " << size << " ]";
216 cb->debug_log(msg.str());
218 #endif
220 // ignore packets smaller than 8 bytes
221 if (size < 8) return;
223 restart_read_timeout();
225 const char* ptr = buf;
226 int action = detail::read_int32(ptr);
227 int transaction = detail::read_int32(ptr);
229 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
230 if (cb)
232 std::stringstream msg;
233 msg << "*** UDP_TRACKER_PACKET [ acton: " << action << " ]";
234 cb->debug_log(msg.str());
236 #endif
238 // ignore packets with incorrect transaction id
239 if (m_transaction_id != transaction) return;
241 if (action == action_error)
243 fail(-1, std::string(ptr, size - 8).c_str());
244 return;
247 // ignore packets that's not a response to our message
248 if (action != m_state) return;
250 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
251 if (cb)
253 std::stringstream msg;
254 msg << "*** UDP_TRACKER_RESPONSE [ cid: " << m_connection_id << " ]";
255 cb->debug_log(msg.str());
257 #endif
259 switch (m_state)
261 case action_connect:
262 on_connect_response(buf, size);
263 break;
264 case action_announce:
265 on_announce_response(buf, size);
266 break;
267 case action_scrape:
268 on_scrape_response(buf, size);
269 break;
270 default: break;
274 void udp_tracker_connection::on_connect_response(char const* buf, int size)
276 // ignore packets smaller than 16 bytes
277 if (size < 16) return;
279 restart_read_timeout();
280 buf += 8; // skip header
282 // reset transaction
283 m_transaction_id = 0;
284 m_attempts = 0;
285 m_connection_id = detail::read_int64(buf);
287 if (tracker_req().kind == tracker_request::announce_request)
288 send_udp_announce();
289 else if (tracker_req().kind == tracker_request::scrape_request)
290 send_udp_scrape();
293 void udp_tracker_connection::send_udp_connect()
295 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
296 boost::shared_ptr<request_callback> cb = requester();
297 if (cb)
299 cb->debug_log("==> UDP_TRACKER_CONNECT ["
300 + lexical_cast<std::string>(tracker_req().info_hash) + "]");
302 #endif
303 if (!m_socket.is_open()) return; // the operation was aborted
305 char buf[16];
306 char* ptr = buf;
308 if (m_transaction_id == 0)
309 m_transaction_id = rand() ^ (rand() << 16);
311 detail::write_uint32(0x417, ptr);
312 detail::write_uint32(0x27101980, ptr); // connection_id
313 detail::write_int32(action_connect, ptr); // action (connect)
314 detail::write_int32(m_transaction_id, ptr); // transaction_id
315 TORRENT_ASSERT(ptr - buf == sizeof(buf));
317 error_code ec;
318 m_socket.send(m_target, buf, 16, ec);
319 m_state = action_connect;
320 ++m_attempts;
321 if (ec)
323 fail(-1, ec.message().c_str());
324 return;
328 void udp_tracker_connection::send_udp_scrape()
330 if (m_transaction_id == 0)
331 m_transaction_id = rand() ^ (rand() << 16);
333 if (!m_socket.is_open()) return; // the operation was aborted
335 char buf[8 + 4 + 4 + 20];
336 char* out = buf;
338 detail::write_int64(m_connection_id, out); // connection_id
339 detail::write_int32(action_scrape, out); // action (scrape)
340 detail::write_int32(m_transaction_id, out); // transaction_id
341 // info_hash
342 std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
343 out += 20;
344 TORRENT_ASSERT(out - buf == sizeof(buf));
346 error_code ec;
347 m_socket.send(m_target, buf, sizeof(buf), ec);
348 m_state = action_scrape;
349 ++m_attempts;
350 if (ec)
352 fail(-1, ec.message().c_str());
353 return;
357 void udp_tracker_connection::on_announce_response(char const* buf, int size)
359 if (size < 20) return;
361 restart_read_timeout();
363 buf += 8; // skip header
364 restart_read_timeout();
365 int interval = detail::read_int32(buf);
366 int incomplete = detail::read_int32(buf);
367 int complete = detail::read_int32(buf);
368 int num_peers = (size - 20) / 6;
369 if ((size - 20) % 6 != 0)
371 fail(-1, "invalid udp tracker response length");
372 return;
375 boost::shared_ptr<request_callback> cb = requester();
376 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
377 if (cb)
379 cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
381 #endif
383 if (!cb)
385 m_man.remove_request(this);
386 return;
389 std::vector<peer_entry> peer_list;
390 for (int i = 0; i < num_peers; ++i)
392 // TODO: don't use a string here
393 peer_entry e;
394 std::stringstream s;
395 s << (int)detail::read_uint8(buf) << ".";
396 s << (int)detail::read_uint8(buf) << ".";
397 s << (int)detail::read_uint8(buf) << ".";
398 s << (int)detail::read_uint8(buf);
399 e.ip = s.str();
400 e.port = detail::read_uint16(buf);
401 e.pid.clear();
402 peer_list.push_back(e);
405 cb->tracker_response(tracker_req(), peer_list, interval
406 , complete, incomplete, address());
408 m_man.remove_request(this);
409 close();
412 void udp_tracker_connection::on_scrape_response(char const* buf, int size)
414 buf += 8; // skip header
416 restart_read_timeout();
417 int action = detail::read_int32(buf);
418 int transaction = detail::read_int32(buf);
420 if (transaction != m_transaction_id)
422 fail(-1, "incorrect transaction id");
423 return;
426 if (action == action_error)
428 fail(-1, std::string(buf, size - 8).c_str());
429 return;
432 if (action != action_scrape)
434 fail(-1, "invalid action in announce response");
435 return;
438 if (size < 20)
440 fail(-1, "got a message with size < 20");
441 return;
444 int complete = detail::read_int32(buf);
445 int downloaded = detail::read_int32(buf);
446 int incomplete = detail::read_int32(buf);
448 boost::shared_ptr<request_callback> cb = requester();
449 if (!cb)
451 close();
452 return;
455 cb->tracker_scrape_response(tracker_req()
456 , complete, incomplete, downloaded);
458 m_man.remove_request(this);
459 close();
462 void udp_tracker_connection::send_udp_announce()
464 if (m_transaction_id == 0)
465 m_transaction_id = rand() ^ (rand() << 16);
467 if (!m_socket.is_open()) return; // the operation was aborted
469 char buf[8 + 4 + 4 + 20 + 20 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 2 + 2];
470 char* out = buf;
472 tracker_request const& req = tracker_req();
474 detail::write_int64(m_connection_id, out); // connection_id
475 detail::write_int32(action_announce, out); // action (announce)
476 detail::write_int32(m_transaction_id, out); // transaction_id
477 std::copy(req.info_hash.begin(), req.info_hash.end(), out); // info_hash
478 out += 20;
479 std::copy(req.pid.begin(), req.pid.end(), out); // peer_id
480 out += 20;
481 detail::write_int64(req.downloaded, out); // downloaded
482 detail::write_int64(req.left, out); // left
483 detail::write_int64(req.uploaded, out); // uploaded
484 detail::write_int32(req.event, out); // event
485 // ip address
486 if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4())
487 detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out);
488 else
489 detail::write_int32(0, out);
490 detail::write_int32(req.key, out); // key
491 detail::write_int32(req.num_want, out); // num_want
492 detail::write_uint16(req.listen_port, out); // port
493 detail::write_uint16(0, out); // extensions
495 TORRENT_ASSERT(out - buf == sizeof(buf));
497 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
498 boost::shared_ptr<request_callback> cb = requester();
499 if (cb)
501 cb->debug_log("==> UDP_TRACKER_ANNOUNCE ["
502 + lexical_cast<std::string>(req.info_hash) + "]");
504 #endif
506 error_code ec;
507 m_socket.send(m_target, buf, sizeof(buf), ec);
508 m_state = action_announce;
509 ++m_attempts;
510 if (ec)
512 fail(-1, ec.message().c_str());
513 return;