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 #include <boost/bind.hpp>
00017
00018 #include "libtorrent/tracker_manager.hpp"
00019 #include "libtorrent/http_tracker_connection.hpp"
00020 #include "libtorrent/udp_tracker_connection.hpp"
00021 #include "libtorrent/entry.hpp"
00022 #include "libtorrent/bencode.hpp"
00023 #include "libtorrent/torrent.hpp"
00024 #include "libtorrent/peer_connection.hpp"
00025
00026 using namespace libtorrent;
00027 using boost::tuples::make_tuple;
00028 using boost::tuples::tuple;
00029 using boost::bind;
00030
00031 namespace
00032 {
00033 enum
00034 {
00035 minimum_tracker_response_length = 3,
00036 http_buffer_size = 2048
00037 };
00038
00039 enum
00040 {
00041 FTEXT = 0x01,
00042 FHCRC = 0x02,
00043 FEXTRA = 0x04,
00044 FNAME = 0x08,
00045 FCOMMENT = 0x10,
00046 FRESERVED = 0xe0,
00047
00048 GZIP_MAGIC0 = 0x1f,
00049 GZIP_MAGIC1 = 0x8b
00050 };
00051
00052 }
00053
00054 namespace libtorrent
00055 {
00056 using boost::posix_time::second_clock;
00057 using boost::posix_time::seconds;
00058 using boost::posix_time::ptime;
00059 using boost::posix_time::time_duration;
00060
00061
00062 int gzip_header(const char* buf, int size)
00063 {
00064 assert(buf != 0);
00065 assert(size > 0);
00066
00067 const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
00068 const int total_size = size;
00069
00070
00071 if (size < 10) return -1;
00072
00073
00074 if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;
00075
00076 int method = buffer[2];
00077 int flags = buffer[3];
00078
00079
00080 if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;
00081
00082
00083 size -= 10;
00084 buffer += 10;
00085
00086 if (flags & FEXTRA)
00087 {
00088 int extra_len;
00089
00090 if (size < 2) return -1;
00091
00092 extra_len = (buffer[1] << 8) | buffer[0];
00093
00094 if (size < (extra_len+2)) return -1;
00095 size -= (extra_len + 2);
00096 buffer += (extra_len + 2);
00097 }
00098
00099 if (flags & FNAME)
00100 {
00101 while (size && *buffer)
00102 {
00103 --size;
00104 ++buffer;
00105 }
00106 if (!size || *buffer) return -1;
00107
00108 --size;
00109 ++buffer;
00110 }
00111
00112 if (flags & FCOMMENT)
00113 {
00114 while (size && *buffer)
00115 {
00116 --size;
00117 ++buffer;
00118 }
00119 if (!size || *buffer) return -1;
00120
00121 --size;
00122 ++buffer;
00123 }
00124
00125 if (flags & FHCRC)
00126 {
00127 if (size < 2) return -1;
00128
00129 size -= 2;
00130 buffer += 2;
00131 }
00132
00133 return total_size - size;
00134 }
00135
00136 bool inflate_gzip(
00137 std::vector<char>& buffer
00138 , tracker_request const& req
00139 , request_callback* requester
00140 , int maximum_tracker_response_length)
00141 {
00142 assert(maximum_tracker_response_length > 0);
00143
00144 int header_len = gzip_header(&buffer[0], (int)buffer.size());
00145 if (header_len < 0)
00146 {
00147 requester->tracker_request_error(req, 200, "invalid gzip header in tracker response");
00148 return true;
00149 }
00150
00151
00152
00153 std::vector<char> inflate_buffer(1024);
00154
00155
00156 z_stream str;
00157
00158
00159
00160 str.avail_in = (int)buffer.size() - header_len - 8;
00161 str.next_in = reinterpret_cast<Bytef*>(&buffer[header_len]);
00162 str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[0]);
00163 str.avail_out = (int)inflate_buffer.size();
00164 str.zalloc = Z_NULL;
00165 str.zfree = Z_NULL;
00166 str.opaque = 0;
00167
00168
00169 if (inflateInit2(&str, -15) != Z_OK)
00170 {
00171 requester->tracker_request_error(req, 200, "gzip out of memory");
00172 return true;
00173 }
00174
00175
00176 int ret = inflate(&str, Z_SYNC_FLUSH);
00177 while (ret == Z_OK)
00178 {
00179 if (str.avail_out == 0)
00180 {
00181 if (inflate_buffer.size() >= (unsigned)maximum_tracker_response_length)
00182 {
00183 inflateEnd(&str);
00184 requester->tracker_request_error(req, 200
00185 , "tracker response too large");
00186 return true;
00187 }
00188 int new_size = (int)inflate_buffer.size() * 2;
00189 if (new_size > maximum_tracker_response_length) new_size = maximum_tracker_response_length;
00190 int old_size = (int)inflate_buffer.size();
00191
00192 inflate_buffer.resize(new_size);
00193 str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[old_size]);
00194 str.avail_out = new_size - old_size;
00195 }
00196
00197 ret = inflate(&str, Z_SYNC_FLUSH);
00198 }
00199
00200 inflate_buffer.resize(inflate_buffer.size() - str.avail_out);
00201 inflateEnd(&str);
00202
00203 if (ret != Z_STREAM_END)
00204 {
00205 requester->tracker_request_error(req, 200, "gzip error");
00206 return true;
00207 }
00208
00209
00210 std::swap(buffer, inflate_buffer);
00211 return false;
00212 }
00213
00214 std::string base64encode(const std::string& s)
00215 {
00216 static const char base64_table[] =
00217 {
00218 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00219 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
00220 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00221 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00222 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00223 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00224 'w', 'x', 'y', 'z', '0', '1', '2', '3',
00225 '4', '5', '6', '7', '8', '9', '+', '/'
00226 };
00227
00228 unsigned char inbuf[3];
00229 unsigned char outbuf[4];
00230
00231 std::string ret;
00232 for (std::string::const_iterator i = s.begin(); i != s.end();)
00233 {
00234
00235
00236 int available_input = std::min(3, (int)std::distance(i, s.end()));
00237
00238
00239 std::fill(inbuf, inbuf+3, 0);
00240
00241
00242 for (int j = 0; j < available_input; ++j)
00243 {
00244 inbuf[j] = *i;
00245 ++i;
00246 }
00247
00248
00249 outbuf[0] = (inbuf[0] & 0xfc) >> 2;
00250 outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
00251 outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
00252 outbuf[3] = inbuf[2] & 0x3f;
00253
00254
00255 for (int j = 0; j < available_input+1; ++j)
00256 {
00257 ret += base64_table[outbuf[j]];
00258 }
00259
00260
00261 for (int j = 0; j < 3 - available_input; ++j)
00262 {
00263 ret += '=';
00264 }
00265 }
00266 return ret;
00267 }
00268
00269 void intrusive_ptr_add_ref(timeout_handler const* c)
00270 {
00271 assert(c != 0);
00272 assert(c->m_refs >= 0);
00273 timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
00274 ++c->m_refs;
00275 }
00276
00277 void intrusive_ptr_release(timeout_handler const* c)
00278 {
00279 assert(c != 0);
00280 assert(c->m_refs > 0);
00281 timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
00282 --c->m_refs;
00283 if (c->m_refs == 0)
00284 {
00285 l.unlock();
00286 delete c;
00287 }
00288 }
00289
00290 timeout_handler::timeout_handler(asio::strand& str)
00291 : m_strand(str)
00292 , m_start_time(second_clock::universal_time())
00293 , m_read_time(second_clock::universal_time())
00294 , m_timeout(str.io_service())
00295 , m_completion_timeout(0)
00296 , m_read_timeout(0)
00297 , m_refs(0)
00298 {}
00299
00300 void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
00301 {
00302 m_completion_timeout = completion_timeout;
00303 m_read_timeout = read_timeout;
00304 m_start_time = second_clock::universal_time();
00305 m_read_time = second_clock::universal_time();
00306
00307 m_timeout.expires_at(std::min(
00308 m_read_time + seconds(m_read_timeout)
00309 , m_start_time + seconds(m_completion_timeout)));
00310 m_timeout.async_wait(m_strand.wrap(bind(
00311 &timeout_handler::timeout_callback, self(), _1)));
00312 }
00313
00314 void timeout_handler::restart_read_timeout()
00315 {
00316 m_read_time = second_clock::universal_time();
00317 }
00318
00319 void timeout_handler::cancel()
00320 {
00321 m_completion_timeout = 0;
00322 m_timeout.cancel();
00323 }
00324
00325 void timeout_handler::timeout_callback(asio::error_code const& error) try
00326 {
00327 if (error) return;
00328 if (m_completion_timeout == 0) return;
00329
00330 ptime now(second_clock::universal_time());
00331 time_duration receive_timeout = now - m_read_time;
00332 time_duration completion_timeout = now - m_start_time;
00333
00334 if (m_read_timeout
00335 < receive_timeout.total_seconds()
00336 || m_completion_timeout
00337 < completion_timeout.total_seconds())
00338 {
00339 on_timeout();
00340 return;
00341 }
00342
00343 m_timeout.expires_at(std::min(
00344 m_read_time + seconds(m_read_timeout)
00345 , m_start_time + seconds(m_completion_timeout)));
00346 m_timeout.async_wait(m_strand.wrap(
00347 bind(&timeout_handler::timeout_callback, self(), _1)));
00348 }
00349 catch (std::exception& e)
00350 {
00351 assert(false);
00352 }
00353
00354 tracker_connection::tracker_connection(
00355 tracker_manager& man
00356 , tracker_request req
00357 , asio::strand& str
00358 , address bind_interface_
00359 , boost::weak_ptr<request_callback> r)
00360 : timeout_handler(str)
00361 , m_requester(r)
00362 , m_bind_interface(bind_interface_)
00363 , m_man(man)
00364 , m_req(req)
00365 {}
00366
00367 request_callback& tracker_connection::requester()
00368 {
00369 boost::shared_ptr<request_callback> r = m_requester.lock();
00370 assert(r);
00371 return *r;
00372 }
00373
00374 void tracker_connection::fail(int code, char const* msg)
00375 {
00376 if (has_requester()) requester().tracker_request_error(
00377 m_req, code, msg);
00378 close();
00379 }
00380
00381 void tracker_connection::fail_timeout()
00382 {
00383 if (has_requester()) requester().tracker_request_timed_out(m_req);
00384 close();
00385 }
00386
00387 void tracker_connection::close()
00388 {
00389 cancel();
00390 m_man.remove_request(this);
00391 }
00392
00393 void tracker_manager::remove_request(tracker_connection const* c)
00394 {
00395 mutex_t::scoped_lock l(m_mutex);
00396
00397 tracker_connections_t::iterator i = std::find(m_connections.begin()
00398 , m_connections.end(), boost::intrusive_ptr<const tracker_connection>(c));
00399 if (i == m_connections.end()) return;
00400
00401 m_connections.erase(i);
00402 }
00403
00404 tuple<std::string, std::string, int, std::string>
00405 parse_url_components(std::string url)
00406 {
00407 std::string hostname;
00408 std::string protocol;
00409 int port = 80;
00410
00411
00412 std::string::iterator start = url.begin();
00413
00414 while (start != url.end() && (*start == ' ' || *start == '\t'))
00415 ++start;
00416 std::string::iterator end
00417 = std::find(url.begin(), url.end(), ':');
00418 protocol = std::string(start, end);
00419
00420 if (end == url.end()) throw std::runtime_error("invalid url");
00421 ++end;
00422 if (end == url.end()) throw std::runtime_error("invalid url");
00423 if (*end != '/') throw std::runtime_error("invalid url");
00424 ++end;
00425 if (end == url.end()) throw std::runtime_error("invalid url");
00426 if (*end != '/') throw std::runtime_error("invalid url");
00427 ++end;
00428 start = end;
00429
00430 end = std::find(start, url.end(), '/');
00431 std::string::iterator port_pos
00432 = std::find(start, url.end(), ':');
00433
00434 if (port_pos < end)
00435 {
00436 hostname.assign(start, port_pos);
00437 ++port_pos;
00438 try
00439 {
00440 port = boost::lexical_cast<int>(std::string(port_pos, end));
00441 }
00442 catch(boost::bad_lexical_cast&)
00443 {
00444 throw std::runtime_error("invalid url: \"" + url
00445 + "\", port number expected");
00446 }
00447 }
00448 else
00449 {
00450 hostname.assign(start, end);
00451 }
00452
00453 start = end;
00454 return make_tuple(protocol, hostname, port
00455 , std::string(start, url.end()));
00456 }
00457
00458 void tracker_manager::queue_request(
00459 asio::strand& str
00460 , tracker_request req
00461 , std::string const& auth
00462 , address bind_infc
00463 , boost::weak_ptr<request_callback> c)
00464 {
00465 mutex_t::scoped_lock l(m_mutex);
00466 assert(req.num_want >= 0);
00467 if (req.event == tracker_request::stopped)
00468 req.num_want = 0;
00469
00470 try
00471 {
00472 std::string protocol;
00473 std::string hostname;
00474 int port;
00475 std::string request_string;
00476
00477 boost::tie(protocol, hostname, port, request_string)
00478 = parse_url_components(req.url);
00479
00480 boost::intrusive_ptr<tracker_connection> con;
00481
00482 if (protocol == "http")
00483 {
00484 con = new http_tracker_connection(
00485 str
00486 , *this
00487 , req
00488 , hostname
00489 , port
00490 , request_string
00491 , bind_infc
00492 , c
00493 , m_settings
00494 , auth);
00495 }
00496 else if (protocol == "udp")
00497 {
00498 con = new udp_tracker_connection(
00499 str
00500 , *this
00501 , req
00502 , hostname
00503 , port
00504 , bind_infc
00505 , c
00506 , m_settings);
00507 }
00508 else
00509 {
00510 throw std::runtime_error("unkown protocol in tracker url");
00511 }
00512
00513 m_connections.push_back(con);
00514
00515 if (con->has_requester()) con->requester().m_manager = this;
00516 }
00517 catch (std::exception& e)
00518 {
00519 if (boost::shared_ptr<request_callback> r = c.lock())
00520 r->tracker_request_error(req, -1, e.what());
00521 }
00522 }
00523
00524 void tracker_manager::abort_all_requests()
00525 {
00526
00527
00528
00529 mutex_t::scoped_lock l(m_mutex);
00530
00531 tracker_connections_t keep_connections;
00532
00533 for (tracker_connections_t::const_iterator i =
00534 m_connections.begin(); i != m_connections.end(); ++i)
00535 {
00536 tracker_request const& req = (*i)->tracker_req();
00537 if (req.event == tracker_request::stopped)
00538 keep_connections.push_back(*i);
00539 }
00540
00541 std::swap(m_connections, keep_connections);
00542 }
00543
00544 bool tracker_manager::empty() const
00545 {
00546 mutex_t::scoped_lock l(m_mutex);
00547 return m_connections.empty();
00548 }
00549
00550 }