3 Copyright (c) 2003, 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.
33 #include "libtorrent/pch.hpp"
44 #pragma warning(push, 1)
47 #include <boost/bind.hpp>
48 #include <boost/lexical_cast.hpp>
54 #include "libtorrent/tracker_manager.hpp"
55 #include "libtorrent/parse_url.hpp"
56 #include "libtorrent/udp_tracker_connection.hpp"
57 #include "libtorrent/io.hpp"
63 udp_connection_retries
= 4,
64 udp_announce_retries
= 15,
65 udp_connect_timeout
= 15,
66 udp_announce_timeout
= 10
71 using boost::lexical_cast
;
76 udp_tracker_connection::udp_tracker_connection(
78 , connection_queue
& cc
79 , tracker_manager
& man
80 , tracker_request
const& req
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
)
88 , m_socket(ios
, boost::bind(&udp_tracker_connection::on_receive
, self(), _1
, _2
, _3
, _4
), cc
)
93 , m_state(action_error
)
95 m_socket
.set_proxy_settings(proxy
);
101 using boost::tuples::ignore
;
102 boost::tie(ignore
, ignore
, hostname
, port
, ignore
, error
)
103 = parse_url_components(req
.url
);
111 udp::resolver::query
q(hostname
, boost::lexical_cast
<std::string
>(port
));
112 m_name_lookup
.async_resolve(q
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());
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());
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 ]");
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
);
151 TORRENT_ASSERT(target_address
.address().is_v4() != bind_interface().is_v4());
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.");
163 target_address
= *target
;
166 if (cb
) cb
->m_tracker_address
= tcp::endpoint(target_address
.address(), target_address
.port());
167 m_target
= target_address
;
169 m_socket
.bind(udp::endpoint(bind_interface(), 0), ec
);
172 fail(-1, ec
.message().c_str());
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 ]");
185 m_name_lookup
.cancel();
189 void udp_tracker_connection::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();
214 std::stringstream msg
;
215 msg
<< "<== UDP_TRACKER_PACKET [ size: " << size
<< " ]";
216 cb
->debug_log(msg
.str());
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
232 std::stringstream msg
;
233 msg
<< "*** UDP_TRACKER_PACKET [ acton: " << action
<< " ]";
234 cb
->debug_log(msg
.str());
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());
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
253 std::stringstream msg
;
254 msg
<< "*** UDP_TRACKER_RESPONSE [ cid: " << m_connection_id
<< " ]";
255 cb
->debug_log(msg
.str());
262 on_connect_response(buf
, size
);
264 case action_announce
:
265 on_announce_response(buf
, size
);
268 on_scrape_response(buf
, size
);
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
283 m_transaction_id
= 0;
285 m_connection_id
= detail::read_int64(buf
);
287 if (tracker_req().kind
== tracker_request::announce_request
)
289 else if (tracker_req().kind
== tracker_request::scrape_request
)
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();
299 cb
->debug_log("==> UDP_TRACKER_CONNECT ["
300 + lexical_cast
<std::string
>(tracker_req().info_hash
) + "]");
303 if (!m_socket
.is_open()) return; // the operation was aborted
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
));
318 m_socket
.send(m_target
, buf
, 16, ec
);
319 m_state
= action_connect
;
323 fail(-1, ec
.message().c_str());
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];
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
342 std::copy(tracker_req().info_hash
.begin(), tracker_req().info_hash
.end(), out
);
344 TORRENT_ASSERT(out
- buf
== sizeof(buf
));
347 m_socket
.send(m_target
, buf
, sizeof(buf
), ec
);
348 m_state
= action_scrape
;
352 fail(-1, ec
.message().c_str());
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");
375 boost::shared_ptr
<request_callback
> cb
= requester();
376 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
379 cb
->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
385 m_man
.remove_request(this);
389 std::vector
<peer_entry
> peer_list
;
390 for (int i
= 0; i
< num_peers
; ++i
)
392 // TODO: don't use a string here
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
);
400 e
.port
= detail::read_uint16(buf
);
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);
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");
426 if (action
== action_error
)
428 fail(-1, std::string(buf
, size
- 8).c_str());
432 if (action
!= action_scrape
)
434 fail(-1, "invalid action in announce response");
440 fail(-1, "got a message with size < 20");
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();
455 cb
->tracker_scrape_response(tracker_req()
456 , complete
, incomplete
, downloaded
);
458 m_man
.remove_request(this);
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];
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
479 std::copy(req
.pid
.begin(), req
.pid
.end(), out
); // peer_id
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
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
);
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();
501 cb
->debug_log("==> UDP_TRACKER_ANNOUNCE ["
502 + lexical_cast
<std::string
>(req
.info_hash
) + "]");
507 m_socket
.send(m_target
, buf
, sizeof(buf
), ec
);
508 m_state
= action_announce
;
512 fail(-1, ec
.message().c_str());