00001
00002
00003
00004
00005
00006
00007
00008 #include <vector>
00009 #include <iostream>
00010 #include <cctype>
00011 #include <iomanip>
00012 #include <sstream>
00013
00014 #include "zlib.h"
00015
00016 #ifdef _MSC_VER
00017 #pragma warning(push, 1)
00018 #endif
00019
00020 #include <boost/bind.hpp>
00021 #include <boost/lexical_cast.hpp>
00022
00023 #ifdef _MSC_VER
00024 #pragma warning(pop)
00025 #endif
00026
00027 #include "libtorrent/tracker_manager.hpp"
00028 #include "libtorrent/udp_tracker_connection.hpp"
00029 #include "libtorrent/io.hpp"
00030
00031 namespace
00032 {
00033 enum
00034 {
00035 udp_connection_retries = 4,
00036 udp_announce_retries = 15,
00037 udp_connect_timeout = 15,
00038 udp_announce_timeout = 10,
00039 udp_buffer_size = 2048
00040 };
00041 }
00042
00043 using namespace boost::posix_time;
00044 using boost::bind;
00045 using boost::lexical_cast;
00046
00047 namespace libtorrent
00048 {
00049
00050 udp_tracker_connection::udp_tracker_connection(
00051 asio::strand& str
00052 , tracker_manager& man
00053 , tracker_request const& req
00054 , std::string const& hostname
00055 , unsigned short port
00056 , address bind_infc
00057 , boost::weak_ptr<request_callback> c
00058 , session_settings const& stn)
00059 : tracker_connection(man, req, str, bind_infc, c)
00060 , m_man(man)
00061 , m_strand(str)
00062 , m_name_lookup(m_strand.io_service())
00063 , m_transaction_id(0)
00064 , m_connection_id(0)
00065 , m_settings(stn)
00066 , m_attempts(0)
00067 {
00068 udp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
00069 m_name_lookup.async_resolve(q
00070 , m_strand.wrap(boost::bind(
00071 &udp_tracker_connection::name_lookup, self(), _1, _2)));
00072 set_timeout(m_settings.tracker_completion_timeout
00073 , m_settings.tracker_receive_timeout);
00074 }
00075
00076 void udp_tracker_connection::name_lookup(asio::error_code const& error
00077 , udp::resolver::iterator i) try
00078 {
00079 if (error == asio::error::operation_aborted) return;
00080 if (!m_socket) return;
00081 if (error || i == udp::resolver::iterator())
00082 {
00083 fail(-1, error.message().c_str());
00084 return;
00085 }
00086
00087 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00088 if (has_requester()) requester().debug_log("udp tracker name lookup successful");
00089 #endif
00090 restart_read_timeout();
00091
00092
00093
00094
00095 udp::resolver::iterator target = i;
00096 udp::resolver::iterator end;
00097 udp::endpoint target_address = *i;
00098 for (; target != end && target->endpoint().address().is_v4()
00099 != bind_interface().is_v4(); ++target);
00100 if (target == end)
00101 {
00102 assert(target_address.address().is_v4() != bind_interface().is_v4());
00103 if (has_requester())
00104 {
00105 std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
00106 std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
00107 requester().tracker_warning("the tracker only resolves to an "
00108 + tracker_address_type + " address, and you're listening on an "
00109 + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
00110 }
00111 }
00112 else
00113 {
00114 target_address = *target;
00115 }
00116
00117 if (has_requester()) requester().m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
00118 m_target = target_address;
00119 m_socket.reset(new datagram_socket(m_name_lookup.io_service()));
00120 m_socket->open(target_address.protocol());
00121 m_socket->bind(udp::endpoint(bind_interface(), 0));
00122 m_socket->connect(target_address);
00123 send_udp_connect();
00124 }
00125 catch (std::exception& e)
00126 {
00127 fail(-1, e.what());
00128 };
00129
00130 void udp_tracker_connection::on_timeout()
00131 {
00132 m_socket.reset();
00133 m_name_lookup.cancel();
00134 fail_timeout();
00135 }
00136
00137 void udp_tracker_connection::send_udp_connect()
00138 {
00139 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00140 if (has_requester())
00141 {
00142 requester().debug_log("==> UDP_TRACKER_CONNECT ["
00143 + lexical_cast<std::string>(tracker_req().info_hash) + "]");
00144 }
00145 #endif
00146 if (!m_socket) return;
00147
00148 char send_buf[16];
00149 char* ptr = send_buf;
00150
00151 if (m_transaction_id == 0)
00152 m_transaction_id = rand() ^ (rand() << 16);
00153
00154
00155 detail::write_uint32(0x417, ptr);
00156 detail::write_uint32(0x27101980, ptr);
00157
00158 detail::write_int32(action_connect, ptr);
00159
00160 detail::write_int32(m_transaction_id, ptr);
00161
00162 m_socket->send(asio::buffer((void*)send_buf, 16), 0);
00163 ++m_attempts;
00164 m_buffer.resize(udp_buffer_size);
00165 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00166 , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
00167 }
00168
00169 void udp_tracker_connection::connect_response(asio::error_code const& error
00170 , std::size_t bytes_transferred) try
00171 {
00172 if (error == asio::error::operation_aborted) return;
00173 if (!m_socket) return;
00174 if (error)
00175 {
00176 fail(-1, error.message().c_str());
00177 return;
00178 }
00179
00180 if (m_target != m_sender)
00181 {
00182
00183 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00184 , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
00185 return;
00186 }
00187
00188 if (bytes_transferred >= udp_buffer_size)
00189 {
00190 fail(-1, "udp response too big");
00191 return;
00192 }
00193
00194 if (bytes_transferred < 8)
00195 {
00196 fail(-1, "got a message with size < 8");
00197 return;
00198 }
00199
00200 restart_read_timeout();
00201
00202 const char* ptr = &m_buffer[0];
00203 int action = detail::read_int32(ptr);
00204 int transaction = detail::read_int32(ptr);
00205
00206 if (action == action_error)
00207 {
00208 fail(-1, std::string(ptr, bytes_transferred - 8).c_str());
00209 return;
00210 }
00211
00212 if (action != action_connect)
00213 {
00214 fail(-1, "invalid action in connect reply");
00215 return;
00216 }
00217
00218 if (m_transaction_id != transaction)
00219 {
00220 fail(-1, "incorrect transaction id");
00221 return;
00222 }
00223
00224 if (bytes_transferred < 16)
00225 {
00226 fail(-1, "udp_tracker_connection: "
00227 "got a message with size < 16");
00228 return;
00229 }
00230
00231 m_transaction_id = 0;
00232 m_attempts = 0;
00233 m_connection_id = detail::read_int64(ptr);
00234
00235 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00236 if (has_requester())
00237 {
00238 requester().debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
00239 + lexical_cast<std::string>(m_connection_id) + "]");
00240 }
00241 #endif
00242
00243 if (tracker_req().kind == tracker_request::announce_request)
00244 send_udp_announce();
00245 else if (tracker_req().kind == tracker_request::scrape_request)
00246 send_udp_scrape();
00247 }
00248 catch (std::exception& e)
00249 {
00250 fail(-1, e.what());
00251 }
00252
00253 void udp_tracker_connection::send_udp_announce()
00254 {
00255 if (m_transaction_id == 0)
00256 m_transaction_id = rand() ^ (rand() << 16);
00257
00258 if (!m_socket) return;
00259
00260 std::vector<char> buf;
00261 std::back_insert_iterator<std::vector<char> > out(buf);
00262
00263 tracker_request const& req = tracker_req();
00264
00265
00266 detail::write_int64(m_connection_id, out);
00267
00268 detail::write_int32(action_announce, out);
00269
00270 detail::write_int32(m_transaction_id, out);
00271
00272 std::copy(req.info_hash.begin(), req.info_hash.end(), out);
00273
00274 std::copy(req.pid.begin(), req.pid.end(), out);
00275
00276 detail::write_int64(req.downloaded, out);
00277
00278 detail::write_int64(req.left, out);
00279
00280 detail::write_int64(req.uploaded, out);
00281
00282 detail::write_int32(req.event, out);
00283
00284 detail::write_int32(0, out);
00285
00286 detail::write_int32(req.key, out);
00287
00288 detail::write_int32(req.num_want, out);
00289
00290 detail::write_uint16(req.listen_port, out);
00291
00292 detail::write_uint16(0, out);
00293
00294 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00295 if (has_requester())
00296 {
00297 requester().debug_log("==> UDP_TRACKER_ANNOUNCE ["
00298 + lexical_cast<std::string>(req.info_hash) + "]");
00299 }
00300 #endif
00301
00302 m_socket->send(asio::buffer(buf), 0);
00303 ++m_attempts;
00304
00305 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00306 , bind(&udp_tracker_connection::announce_response, self(), _1, _2));
00307 }
00308
00309 void udp_tracker_connection::send_udp_scrape()
00310 {
00311 if (m_transaction_id == 0)
00312 m_transaction_id = rand() ^ (rand() << 16);
00313
00314 if (!m_socket) return;
00315
00316 std::vector<char> buf;
00317 std::back_insert_iterator<std::vector<char> > out(buf);
00318
00319
00320 detail::write_int64(m_connection_id, out);
00321
00322 detail::write_int32(action_scrape, out);
00323
00324 detail::write_int32(m_transaction_id, out);
00325
00326 std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
00327
00328 m_socket->send(asio::buffer(&buf[0], buf.size()), 0);
00329 ++m_attempts;
00330
00331 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00332 , bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
00333 }
00334
00335 void udp_tracker_connection::announce_response(asio::error_code const& error
00336 , std::size_t bytes_transferred) try
00337 {
00338 if (error == asio::error::operation_aborted) return;
00339 if (!m_socket) return;
00340 if (error)
00341 {
00342 fail(-1, error.message().c_str());
00343 return;
00344 }
00345
00346 if (m_target != m_sender)
00347 {
00348
00349 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00350 , bind(&udp_tracker_connection::connect_response, self(), _1, _2));
00351 return;
00352 }
00353
00354 if (bytes_transferred >= udp_buffer_size)
00355 {
00356 fail(-1, "udp response too big");
00357 return;
00358 }
00359
00360 if (bytes_transferred < 8)
00361 {
00362 fail(-1, "got a message with size < 8");
00363 return;
00364 }
00365
00366 restart_read_timeout();
00367 char* buf = &m_buffer[0];
00368 int action = detail::read_int32(buf);
00369 int transaction = detail::read_int32(buf);
00370
00371 if (transaction != m_transaction_id)
00372 {
00373 fail(-1, "incorrect transaction id");
00374 return;
00375 }
00376
00377 if (action == action_error)
00378 {
00379 fail(-1, std::string(buf, bytes_transferred - 8).c_str());
00380 return;
00381 }
00382
00383 if (action != action_announce)
00384 {
00385 fail(-1, "invalid action in announce response");
00386 return;
00387 }
00388
00389 if (bytes_transferred < 20)
00390 {
00391 fail(-1, "got a message with size < 20");
00392 return;
00393 }
00394
00395 int interval = detail::read_int32(buf);
00396 int incomplete = detail::read_int32(buf);
00397 int complete = detail::read_int32(buf);
00398 int num_peers = (bytes_transferred - 20) / 6;
00399 if ((bytes_transferred - 20) % 6 != 0)
00400 {
00401 fail(-1, "invalid udp tracker response length");
00402 return;
00403 }
00404
00405 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00406 if (has_requester())
00407 {
00408 requester().debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
00409 }
00410 #endif
00411
00412 if (!has_requester())
00413 {
00414 m_man.remove_request(this);
00415 return;
00416 }
00417
00418 std::vector<peer_entry> peer_list;
00419 for (int i = 0; i < num_peers; ++i)
00420 {
00421 peer_entry e;
00422 std::stringstream s;
00423 s << (int)detail::read_uint8(buf) << ".";
00424 s << (int)detail::read_uint8(buf) << ".";
00425 s << (int)detail::read_uint8(buf) << ".";
00426 s << (int)detail::read_uint8(buf);
00427 e.ip = s.str();
00428 e.port = detail::read_uint16(buf);
00429 e.pid.clear();
00430 peer_list.push_back(e);
00431 }
00432
00433 requester().tracker_response(tracker_req(), peer_list, interval
00434 , complete, incomplete);
00435
00436 m_man.remove_request(this);
00437 return;
00438 }
00439 catch (std::exception& e)
00440 {
00441 fail(-1, e.what());
00442 };
00443
00444 void udp_tracker_connection::scrape_response(asio::error_code const& error
00445 , std::size_t bytes_transferred) try
00446 {
00447 if (error == asio::error::operation_aborted) return;
00448 if (!m_socket) return;
00449 if (error)
00450 {
00451 fail(-1, error.message().c_str());
00452 return;
00453 }
00454
00455 if (m_target != m_sender)
00456 {
00457
00458 m_socket->async_receive_from(asio::buffer(m_buffer), m_sender
00459 , bind(&udp_tracker_connection::connect_response, self(), _1, _2));
00460 return;
00461 }
00462
00463 if (bytes_transferred >= udp_buffer_size)
00464 {
00465 fail(-1, "udp response too big");
00466 return;
00467 }
00468
00469 if (bytes_transferred < 8)
00470 {
00471 fail(-1, "got a message with size < 8");
00472 return;
00473 }
00474
00475 restart_read_timeout();
00476 char* buf = &m_buffer[0];
00477 int action = detail::read_int32(buf);
00478 int transaction = detail::read_int32(buf);
00479
00480 if (transaction != m_transaction_id)
00481 {
00482 fail(-1, "incorrect transaction id");
00483 return;
00484 }
00485
00486 if (action == action_error)
00487 {
00488 fail(-1, std::string(buf, bytes_transferred - 8).c_str());
00489 return;
00490 }
00491
00492 if (action != action_scrape)
00493 {
00494 fail(-1, "invalid action in announce response");
00495 return;
00496 }
00497
00498 if (bytes_transferred < 20)
00499 {
00500 fail(-1, "got a message with size < 20");
00501 return;
00502 }
00503
00504 int complete = detail::read_int32(buf);
00505 detail::read_int32(buf);
00506 int incomplete = detail::read_int32(buf);
00507
00508 if (!has_requester())
00509 {
00510 m_man.remove_request(this);
00511 return;
00512 }
00513
00514 std::vector<peer_entry> peer_list;
00515 requester().tracker_response(tracker_req(), peer_list, 0
00516 , complete, incomplete);
00517
00518 m_man.remove_request(this);
00519 }
00520 catch (std::exception& e)
00521 {
00522 fail(-1, e.what());
00523 }
00524
00525 }
00526