00001
00002
00003
00004
00005
00006
00007
00008 #include <iostream>
00009 #include <fstream>
00010 #include <iterator>
00011 #include <exception>
00012
00013 #include "libtorrent/config.hpp"
00014
00015 #ifdef _MSC_VER
00016 #pragma warning(push, 1)
00017 #endif
00018
00019 #include <boost/filesystem/operations.hpp>
00020 #include <boost/filesystem/fstream.hpp>
00021 #include <boost/filesystem/exception.hpp>
00022 #include <boost/date_time/posix_time/posix_time.hpp>
00023 #include <boost/bind.hpp>
00024 #include <boost/program_options.hpp>
00025 #include <boost/regex.hpp>
00026
00027 #ifdef _MSC_VER
00028 #pragma warning(pop)
00029 #endif
00030
00031 #include "libtorrent/extensions/metadata_transfer.hpp"
00032 #include "libtorrent/extensions/ut_pex.hpp"
00033
00034 #include "libtorrent/entry.hpp"
00035 #include "libtorrent/bencode.hpp"
00036 #include "libtorrent/session.hpp"
00037 #include "libtorrent/identify_client.hpp"
00038 #include "libtorrent/alert_types.hpp"
00039 #include "libtorrent/ip_filter.hpp"
00040
00041 using boost::bind;
00042
00043 #ifdef _WIN32
00044
00045 #if defined(_MSC_VER)
00046 # define for if (false) {} else for
00047 #endif
00048
00049 #include <windows.h>
00050 #include <conio.h>
00051
00052 bool sleep_and_input(char* c)
00053 {
00054 Sleep(500);
00055 if (_kbhit())
00056 {
00057 *c = _getch();
00058 return true;
00059 }
00060 return false;
00061 };
00062
00063 void clear_home()
00064 {
00065 CONSOLE_SCREEN_BUFFER_INFO si;
00066 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
00067 GetConsoleScreenBufferInfo(h, &si);
00068 COORD c = {0, 0};
00069 DWORD n;
00070 FillConsoleOutputCharacter(h, ' ', si.dwSize.X * si.dwSize.Y, c, &n);
00071 SetConsoleCursorPosition(h, c);
00072 }
00073
00074 #else
00075
00076 #include <stdlib.h>
00077 #include <stdio.h>
00078
00079 #include <termios.h>
00080 #include <string.h>
00081
00082 #define ANSI_TERMINAL_COLORS
00083
00084 struct set_keypress
00085 {
00086 set_keypress()
00087 {
00088 termios new_settings;
00089 tcgetattr(0,&stored_settings);
00090 new_settings = stored_settings;
00091
00092 new_settings.c_lflag &= (~ICANON);
00093 new_settings.c_cc[VTIME] = 0;
00094 new_settings.c_cc[VMIN] = 1;
00095 tcsetattr(0,TCSANOW,&new_settings);
00096 }
00097 ~set_keypress() { tcsetattr(0,TCSANOW,&stored_settings); }
00098 termios stored_settings;
00099 };
00100
00101 bool sleep_and_input(char* c)
00102 {
00103
00104
00105 set_keypress s;
00106
00107 fd_set set;
00108 FD_ZERO(&set);
00109 FD_SET(0, &set);
00110 timeval tv = {0, 500000};
00111 if (select(1, &set, 0, 0, &tv) > 0)
00112 {
00113 *c = getc(stdin);
00114 return true;
00115 }
00116 return false;
00117 }
00118
00119 void clear_home()
00120 {
00121 std::cout << "\033[2J\033[0;0H";
00122 }
00123
00124 #endif
00125
00126 std::string esc(char const* code)
00127 {
00128 #ifdef ANSI_TERMINAL_COLORS
00129 std::string ret;
00130 ret += char(0x1b);
00131 ret += "[";
00132 ret += code;
00133 ret += "m";
00134 return ret;
00135 #else
00136 return std::string();
00137 #endif
00138 }
00139
00140 std::string to_string(float v, int width, int precision = 3)
00141 {
00142 std::stringstream s;
00143 s.precision(precision);
00144 s.flags(std::ios_base::right);
00145 s.width(width);
00146 s.fill(' ');
00147 s << v;
00148 return s.str();
00149 }
00150
00151 std::string pos_to_string(float v, int width, int precision = 4)
00152 {
00153 std::stringstream s;
00154 s.precision(precision);
00155 s.flags(std::ios_base::right);
00156 s.width(width);
00157 s.fill(' ');
00158 s << fabs(v);
00159 return s.str();
00160 }
00161
00162 std::string ratio(float a, float b)
00163 {
00164 std::stringstream s;
00165 if (a > b)
00166 {
00167 if (b < 0.001f) s << " inf:1";
00168 else s << pos_to_string(a/b, 4) << ":1";
00169 }
00170 else if (a < b)
00171 {
00172 if (a < 0.001f) s << " 1:inf";
00173 else s << "1:" << pos_to_string(b/a, 4);
00174 }
00175 else
00176 {
00177 s << " 1:1";
00178 }
00179
00180 return s.str();
00181 }
00182
00183 std::string add_suffix(float val)
00184 {
00185 const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
00186 const int num_prefix = sizeof(prefix) / sizeof(const char*);
00187 for (int i = 0; i < num_prefix; ++i)
00188 {
00189 if (fabs(val) < 1000.f)
00190 return to_string(val, i==0?5:4) + prefix[i];
00191 val /= 1000.f;
00192 }
00193 return to_string(val, 6) + "PB";
00194 }
00195
00196 std::string progress_bar(float progress, int width, char const* code = "33")
00197 {
00198 std::string bar;
00199 bar.reserve(width);
00200
00201 int progress_chars = static_cast<int>(progress * width + .5f);
00202 bar = esc(code);
00203 std::fill_n(std::back_inserter(bar), progress_chars, '#');
00204 bar += esc("0");
00205 std::fill_n(std::back_inserter(bar), width - progress_chars, '-');
00206 return std::string(bar.begin(), bar.end());
00207 }
00208
00209 int peer_index(libtorrent::tcp::endpoint addr, std::vector<libtorrent::peer_info> const& peers)
00210 {
00211 using namespace libtorrent;
00212 std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
00213 , peers.end(), boost::bind(std::equal_to<libtorrent::tcp::endpoint>()
00214 , bind(&peer_info::ip, _1), addr));
00215 if (i == peers.end()) return -1;
00216
00217 return i - peers.begin();
00218 }
00219
00220 void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const& peers)
00221 {
00222 using namespace libtorrent;
00223 #ifndef ANSI_TERMINAL_COLORS
00224 out << " down (total) up (total) q r flags block progress country client \n";
00225 #endif
00226
00227 for (std::vector<peer_info>::const_iterator i = peers.begin();
00228 i != peers.end(); ++i)
00229 {
00230 out.fill(' ');
00231 out.width(2);
00232 out << esc("32") << (i->down_speed > 0 ? add_suffix(i->down_speed) + "/s " : " ")
00233 << "(" << add_suffix(i->total_download) << ") " << esc("0")
00234 << esc("31") << (i->up_speed > 0 ? add_suffix(i->up_speed) + "/s ": " ")
00235 << "(" << add_suffix(i->total_upload) << ") " << esc("0")
00236 << to_string(i->download_queue_length, 2, 2) << " "
00237 << to_string(i->upload_queue_length, 2, 2) << " "
00238 << ((i->flags & peer_info::interesting)?'I':'.')
00239 << ((i->flags & peer_info::choked)?'C':'.')
00240 << ((i->flags & peer_info::remote_interested)?'i':'.')
00241 << ((i->flags & peer_info::remote_choked)?'c':'.')
00242 << ((i->flags & peer_info::supports_extensions)?'e':'.')
00243 << ((i->flags & peer_info::local_connection)?'l':'r') << " ";
00244
00245 if (i->downloading_piece_index >= 0)
00246 {
00247 out << progress_bar(
00248 i->downloading_progress / float(i->downloading_total), 15);
00249 }
00250 else
00251 {
00252 out << progress_bar(0.f, 15);
00253 }
00254
00255 if (i->country[0] == 0)
00256 {
00257 out << " ..";
00258 }
00259 else
00260 {
00261 out << " " << i->country[0] << i->country[1];
00262 }
00263
00264 if (i->flags & peer_info::handshake)
00265 {
00266 out << esc("31") << " waiting for handshake" << esc("0") << "\n";
00267 }
00268 else if (i->flags & peer_info::connecting)
00269 {
00270 out << esc("31") << " connecting to peer" << esc("0") << "\n";
00271 }
00272 else if (i->flags & peer_info::queued)
00273 {
00274 out << esc("33") << " queued" << esc("0") << "\n";
00275 }
00276 else
00277 {
00278 out << " " << i->client << "\n";
00279 }
00280 }
00281 }
00282
00283 typedef std::multimap<std::string, libtorrent::torrent_handle> handles_t;
00284
00285 using boost::posix_time::ptime;
00286 using boost::posix_time::second_clock;
00287 using boost::posix_time::seconds;
00288 using boost::bind;
00289 using boost::filesystem::path;
00290 using boost::filesystem::exists;
00291 using boost::filesystem::no_check;
00292 using boost::filesystem::directory_iterator;
00293 using boost::filesystem::extension;
00294
00295 void add_torrent(libtorrent::session& ses
00296 , handles_t& handles
00297 , std::string const& torrent
00298 , float preferred_ratio
00299 , bool compact_mode
00300 , path const& save_path
00301 , bool monitored_dir) try
00302 {
00303 using namespace libtorrent;
00304
00305 std::ifstream in(torrent.c_str(), std::ios_base::binary);
00306 in.unsetf(std::ios_base::skipws);
00307 entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
00308 torrent_info t(e);
00309
00310 std::cout << t.name() << "\n";
00311
00312 entry resume_data;
00313 try
00314 {
00315 std::stringstream s;
00316 s << t.name() << ".fastresume";
00317 boost::filesystem::ifstream resume_file(save_path / s.str(), std::ios_base::binary);
00318 resume_file.unsetf(std::ios_base::skipws);
00319 resume_data = bdecode(
00320 std::istream_iterator<char>(resume_file)
00321 , std::istream_iterator<char>());
00322 }
00323 catch (invalid_encoding&) {}
00324 catch (boost::filesystem::filesystem_error&) {}
00325
00326 torrent_handle h = ses.add_torrent(t, save_path, resume_data
00327 , compact_mode, 16 * 1024);
00328 handles.insert(std::make_pair(
00329 monitored_dir?std::string(torrent):std::string(), h));
00330
00331 h.set_max_connections(60);
00332 h.set_max_uploads(-1);
00333 h.set_ratio(preferred_ratio);
00334 h.set_sequenced_download_threshold(15);
00335 h.resolve_countries(true);
00336 }
00337 catch (std::exception&) {};
00338
00339 void scan_dir(path const& dir_path
00340 , libtorrent::session& ses
00341 , handles_t& handles
00342 , float preferred_ratio
00343 , bool compact_mode
00344 , path const& save_path)
00345 {
00346 std::set<std::string> valid;
00347
00348 using namespace libtorrent;
00349
00350 for (directory_iterator i(dir_path), end; i != end; ++i)
00351 {
00352 if (extension(*i) != ".torrent") continue;
00353 std::string file = i->string();
00354
00355 handles_t::iterator k = handles.find(file);
00356 if (k != handles.end())
00357 {
00358 valid.insert(file);
00359 continue;
00360 }
00361
00362
00363
00364 add_torrent(ses, handles, file, preferred_ratio, compact_mode
00365 , save_path, true);
00366 valid.insert(file);
00367 }
00368
00369
00370
00371 for (handles_t::iterator i = handles.begin()
00372 , end(handles.end()); i != end; ++i)
00373 {
00374 if (i->first.empty()) continue;
00375 if (valid.find(i->first) != valid.end()) continue;
00376
00377 torrent_handle& h = i->second;
00378 if (!h.is_valid())
00379 {
00380 handles.erase(i--);
00381 continue;
00382 }
00383
00384 h.pause();
00385 if (h.has_metadata())
00386 {
00387 entry data = h.write_resume_data();
00388 std::stringstream s;
00389 s << h.get_torrent_info().name() << ".fastresume";
00390 boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
00391 out.unsetf(std::ios_base::skipws);
00392 bencode(std::ostream_iterator<char>(out), data);
00393 }
00394 ses.remove_torrent(h);
00395 handles.erase(i--);
00396 }
00397 }
00398
00399 int main(int ac, char* av[])
00400 {
00401 path::default_name_check(no_check);
00402
00403 int listen_port;
00404 float preferred_ratio;
00405 int download_limit;
00406 int upload_limit;
00407 int upload_slots_limit;
00408 int half_open_limit;
00409 std::string save_path_str;
00410 std::string log_level;
00411 std::string ip_filter_file;
00412 std::string allocation_mode;
00413 std::string in_monitor_dir;
00414 std::string bind_to_interface;
00415 std::string proxy;
00416 std::string proxy_login;
00417 int poll_interval;
00418
00419 namespace po = boost::program_options;
00420 try
00421 {
00422
00423 po::options_description desc("supported options");
00424 desc.add_options()
00425 ("help,h", "display this help message")
00426 ("port,p", po::value<int>(&listen_port)->default_value(6881)
00427 , "set listening port")
00428 ("ratio,r", po::value<float>(&preferred_ratio)->default_value(0)
00429 , "set the preferred upload/download ratio. 0 means infinite. Values "
00430 "smaller than 1 are clamped to 1.")
00431 ("max-download-rate,d", po::value<int>(&download_limit)->default_value(0)
00432 , "the maximum download rate given in kB/s. 0 means infinite.")
00433 ("max-upload-rate,u", po::value<int>(&upload_limit)->default_value(0)
00434 , "the maximum upload rate given in kB/s. 0 means infinite.")
00435 ("max-upload-slots", po::value<int>(&upload_slots_limit)->default_value(8)
00436 , "the maximum number of upload slots. 0 means infinite.")
00437 ("save-path,s", po::value<std::string>(&save_path_str)->default_value("./")
00438 , "the path where the downloaded file/folder should be placed.")
00439 ("log-level,l", po::value<std::string>(&log_level)->default_value("info")
00440 , "sets the level at which events are logged [debug | info | warning | fatal].")
00441 ("ip-filter,f", po::value<std::string>(&ip_filter_file)->default_value("")
00442 , "sets the path to the ip-filter file used to block access from certain "
00443 "ips. ")
00444 ("allocation-mode,a", po::value<std::string>(&allocation_mode)->default_value("compact")
00445 , "sets mode used for allocating the downloaded files on disk. "
00446 "Possible options are [full | compact]")
00447 ("input-file,i", po::value<std::vector<std::string> >()
00448 , "adds an input .torrent file. At least one is required. arguments "
00449 "without any flag are implicitly an input file. To start a torrentless "
00450 "download, use <info-hash>@<tracker-url> instead of specifying a file.")
00451 ("monitor-dir,m", po::value<std::string>(&in_monitor_dir)
00452 , "monitors the given directory, looking for .torrent files and "
00453 "automatically starts downloading them. It will stop downloading "
00454 "torrent files that are removed from the directory")
00455 ("poll-interval,t", po::value<int>(&poll_interval)->default_value(2)
00456 , "if a directory is being monitored, this is the interval (given "
00457 "in seconds) between two refreshes of the directory listing")
00458 ("half-open-limit,o", po::value<int>(&half_open_limit)->default_value(-1)
00459 , "Sets the maximum number of simultaneous half-open tcp connections")
00460 ("bind,b", po::value<std::string>(&bind_to_interface)->default_value("")
00461 , "Sets the local interface to bind outbound and the listen "
00462 "socket to")
00463 ("proxy-server,x", po::value<std::string>(&proxy)->default_value("")
00464 , "Sets the http proxy to be used for tracker and web seeds "
00465 "connections. The string is expected to be on the form: "
00466 "<hostname>:<port>. If no port is specified, 8080 is assumed")
00467 ("proxy-login,n", po::value<std::string>(&proxy_login)->default_value("")
00468 , "Sets the username and password used to authenticate with the http "
00469 "proxy. The string should be given in the form: <username>:<password>")
00470 ;
00471
00472 po::positional_options_description p;
00473 p.add("input-file", -1);
00474
00475 po::variables_map vm;
00476 po::store(po::command_line_parser(ac, av).
00477 options(desc).positional(p).run(), vm);
00478 po::notify(vm);
00479
00480
00481 path monitor_dir(in_monitor_dir);
00482 if (listen_port < 0 || listen_port > 65525) listen_port = 6881;
00483 if (preferred_ratio != 0 && preferred_ratio < 1.f) preferred_ratio = 1.f;
00484 upload_limit *= 1000;
00485 download_limit *= 1000;
00486 if (download_limit <= 0) download_limit = -1;
00487 if (upload_limit <= 0) upload_limit = -1;
00488 if (poll_interval < 2) poll_interval = 2;
00489 if (half_open_limit < 1) half_open_limit = -1;
00490 if (upload_slots_limit <= 0) upload_slots_limit = -1;
00491 if (!monitor_dir.empty() && !exists(monitor_dir))
00492 {
00493 std::cerr << "The monitor directory doesn't exist: " << monitor_dir.string() << std::endl;
00494 return 1;
00495 }
00496
00497 if (vm.count("help")
00498 || vm.count("input-file") + vm.count("monitor-dir") == 0)
00499 {
00500 std::cout << desc << "\n";
00501 return 1;
00502 }
00503
00504 bool compact_allocation_mode = (allocation_mode == "compact");
00505
00506 using namespace libtorrent;
00507
00508 std::vector<std::string> input;
00509 if (vm.count("input-file") > 0)
00510 input = vm["input-file"].as< std::vector<std::string> >();
00511
00512 session_settings settings;
00513
00514 if (!proxy.empty())
00515 {
00516 try
00517 {
00518 std::size_t i = proxy.find(':');
00519 settings.proxy_ip = proxy.substr(0, i);
00520 if (i == std::string::npos) settings.proxy_port = 8080;
00521 else settings.proxy_port = boost::lexical_cast<int>(
00522 proxy.substr(i + 1));
00523 }
00524 catch (std::exception&)
00525 {
00526 std::cerr << "Proxy hostname did not match the required format: "
00527 << proxy << std::endl;
00528 return 1;
00529 }
00530
00531 if (!proxy_login.empty())
00532 {
00533 std::size_t i = proxy_login.find(':');
00534 if (i == std::string::npos)
00535 {
00536 std::cerr << "Proxy login did not match the required format: "
00537 << proxy_login << std::endl;
00538 return 1;
00539 }
00540 settings.proxy_login = proxy_login.substr(0, i);
00541 settings.proxy_password = proxy_login.substr(i + 1);
00542 }
00543 }
00544
00545 settings.user_agent = "client_test/" LIBTORRENT_VERSION;
00546
00547 std::deque<std::string> events;
00548
00549 ptime next_dir_scan = second_clock::universal_time();
00550
00551
00552
00553
00554
00555 handles_t handles;
00556 session ses;
00557 ses.add_extension(&create_metadata_plugin);
00558 ses.add_extension(&create_ut_pex_plugin);
00559
00560 #ifndef TORRENT_DISABLE_DHT
00561 settings.use_dht_as_fallback = false;
00562
00563 dht_settings s;
00564 s.service_port = listen_port;
00565 ses.set_dht_settings(s);
00566 boost::filesystem::ifstream dht_state_file(".dht_state"
00567 , std::ios_base::binary);
00568 dht_state_file.unsetf(std::ios_base::skipws);
00569 entry dht_state;
00570 try
00571 {
00572 dht_state = bdecode(
00573 std::istream_iterator<char>(dht_state_file)
00574 , std::istream_iterator<char>());
00575 }
00576 catch (std::exception&) {}
00577 ses.start_dht(dht_state);
00578 ses.add_dht_router(std::make_pair(std::string("router.bittorrent.com")
00579 , 6881));
00580 ses.add_dht_router(std::make_pair(std::string("router.utorrent.com")
00581 , 6881));
00582 ses.add_dht_router(std::make_pair(std::string("router.bitcomet.com")
00583 , 6881));
00584 #endif
00585
00586 ses.set_max_uploads(upload_slots_limit);
00587 ses.set_max_half_open_connections(half_open_limit);
00588 ses.set_download_rate_limit(download_limit);
00589 ses.set_upload_rate_limit(upload_limit);
00590 ses.listen_on(std::make_pair(listen_port, listen_port + 10)
00591 , bind_to_interface.c_str());
00592 ses.set_settings(settings);
00593 if (log_level == "debug")
00594 ses.set_severity_level(alert::debug);
00595 else if (log_level == "warning")
00596 ses.set_severity_level(alert::warning);
00597 else if (log_level == "fatal")
00598 ses.set_severity_level(alert::fatal);
00599 else
00600 ses.set_severity_level(alert::info);
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 if (!ip_filter_file.empty())
00622 {
00623 std::ifstream in(ip_filter_file.c_str());
00624 ip_filter filter;
00625 while (in.good())
00626 {
00627 char line[300];
00628 in.getline(line, 300);
00629 int len = in.gcount();
00630 if (len <= 0) continue;
00631 if (line[0] == '#') continue;
00632 int a, b, c, d;
00633 char dummy;
00634 in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
00635 address_v4 start((a << 24) + (b << 16) + (c << 8) + d);
00636 in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
00637 address_v4 last((a << 24) + (b << 16) + (c << 8) + d);
00638 int flags;
00639 in >> flags;
00640 if (flags <= 127) flags = ip_filter::blocked;
00641 else flags = 0;
00642 if (in.fail()) break;
00643 filter.add_rule(start, last, flags);
00644 }
00645 ses.set_ip_filter(filter);
00646 }
00647 boost::filesystem::path save_path(save_path_str);
00648
00649
00650 boost::regex ex("([0-9A-Fa-f]{40})@(.+)");
00651 for (std::vector<std::string>::const_iterator i = input.begin();
00652 i != input.end(); ++i)
00653 {
00654 try
00655 {
00656
00657 boost::cmatch what;
00658 if (boost::regex_match(i->c_str(), what, ex))
00659 {
00660 sha1_hash info_hash = boost::lexical_cast<sha1_hash>(what[1]);
00661
00662 torrent_handle h = ses.add_torrent(std::string(what[2]).c_str()
00663 , info_hash, 0, save_path, entry(), compact_allocation_mode);
00664 handles.insert(std::make_pair(std::string(), h));
00665
00666 h.set_max_connections(60);
00667 h.set_max_uploads(-1);
00668 h.set_ratio(preferred_ratio);
00669 h.set_sequenced_download_threshold(15);
00670 continue;
00671 }
00672
00673 add_torrent(ses, handles, i->c_str(), preferred_ratio
00674 , compact_allocation_mode, save_path, false);
00675 }
00676 catch (std::exception& e)
00677 {
00678 std::cout << e.what() << "\n";
00679 }
00680 }
00681
00682
00683 std::vector<peer_info> peers;
00684 std::vector<partial_piece_info> queue;
00685
00686 bool print_peers = false;
00687 bool print_log = false;
00688 bool print_downloads = false;
00689 bool print_file_progress = false;
00690
00691 for (;;)
00692 {
00693 char c;
00694 if (sleep_and_input(&c))
00695 {
00696 if (c == 'q')
00697 {
00698 for (handles_t::iterator i = handles.begin();
00699 i != handles.end(); ++i)
00700 {
00701 torrent_handle& h = i->second;
00702 if (!h.is_valid() || !h.has_metadata()) continue;
00703
00704 h.pause();
00705
00706 entry data = h.write_resume_data();
00707 std::stringstream s;
00708 s << h.get_torrent_info().name() << ".fastresume";
00709 boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
00710 out.unsetf(std::ios_base::skipws);
00711 bencode(std::ostream_iterator<char>(out), data);
00712 ses.remove_torrent(h);
00713 }
00714 break;
00715 }
00716
00717 if(c == 'r')
00718 {
00719
00720 std::for_each(handles.begin(), handles.end()
00721 , bind(&torrent_handle::force_reannounce
00722 , bind(&handles_t::value_type::second, _1)));
00723 }
00724
00725 if(c == 'p')
00726 {
00727
00728 std::for_each(handles.begin(), handles.end()
00729 , bind(&torrent_handle::pause
00730 , bind(&handles_t::value_type::second, _1)));
00731 }
00732
00733 if(c == 'u')
00734 {
00735
00736 std::for_each(handles.begin(), handles.end()
00737 , bind(&torrent_handle::resume
00738 , bind(&handles_t::value_type::second, _1)));
00739 }
00740
00741 if (c == 'i') print_peers = !print_peers;
00742 if (c == 'l') print_log = !print_log;
00743 if (c == 'd') print_downloads = !print_downloads;
00744 if (c == 'f') print_file_progress = !print_file_progress;
00745 }
00746
00747
00748 std::auto_ptr<alert> a;
00749 a = ses.pop_alert();
00750 std::string now = to_simple_string(second_clock::universal_time());
00751 while (a.get())
00752 {
00753 if (torrent_finished_alert* p = dynamic_cast<torrent_finished_alert*>(a.get()))
00754 {
00755 p->handle.set_max_connections(60);
00756
00757
00758 torrent_handle h = p->handle;
00759 entry data = h.write_resume_data();
00760 std::stringstream s;
00761 s << h.get_torrent_info().name() << ".fastresume";
00762 boost::filesystem::ofstream out(h.save_path() / s.str(), std::ios_base::binary);
00763 out.unsetf(std::ios_base::skipws);
00764 bencode(std::ostream_iterator<char>(out), data);
00765
00766 events.push_back(now + ": "
00767 + p->handle.get_torrent_info().name() + ": " + a->msg());
00768 }
00769 else if (peer_error_alert* p = dynamic_cast<peer_error_alert*>(a.get()))
00770 {
00771 events.push_back(now + ": " + identify_client(p->pid)
00772 + ": " + a->msg());
00773 }
00774 else if (invalid_request_alert* p = dynamic_cast<invalid_request_alert*>(a.get()))
00775 {
00776 events.push_back(now + ": " + identify_client(p->pid)
00777 + ": " + a->msg());
00778 }
00779 else if (tracker_warning_alert* p = dynamic_cast<tracker_warning_alert*>(a.get()))
00780 {
00781 events.push_back(now + ": tracker message: " + p->msg());
00782 }
00783 else if (tracker_reply_alert* p = dynamic_cast<tracker_reply_alert*>(a.get()))
00784 {
00785 events.push_back(now + ": " + p->msg() + " ("
00786 + boost::lexical_cast<std::string>(p->num_peers) + ")");
00787 }
00788 else if (url_seed_alert* p = dynamic_cast<url_seed_alert*>(a.get()))
00789 {
00790 events.push_back(now + ": web seed '" + p->url + "': "+ p->msg());
00791 }
00792 else
00793 {
00794 events.push_back(now + ": " + a->msg());
00795 }
00796
00797 if (events.size() >= 10) events.pop_front();
00798 a = ses.pop_alert();
00799 }
00800
00801 session_status sess_stat = ses.status();
00802
00803 std::stringstream out;
00804 for (handles_t::iterator i = handles.begin();
00805 i != handles.end();)
00806 {
00807 torrent_handle& h = i->second;
00808 if (!h.is_valid())
00809 {
00810 handles.erase(i++);
00811 continue;
00812 }
00813 else
00814 {
00815 ++i;
00816 }
00817
00818 out << "- " << esc("37") << std::setw(40)
00819 << std::setiosflags(std::ios::left);
00820 if (h.has_metadata())
00821 {
00822 std::string name = h.get_torrent_info().name();
00823 if (name.size() > 40) name.resize(40);
00824 out << name;
00825 }
00826 else
00827 {
00828 out << "-";
00829 }
00830 out << esc("0") << " ";
00831 torrent_status s = h.status();
00832
00833 if (s.state != torrent_status::seeding)
00834 {
00835 static char const* state_str[] =
00836 {"queued", "checking", "connecting", "downloading metadata"
00837 , "downloading", "finished", "seeding", "allocating"};
00838 out << state_str[s.state] << " ";
00839 }
00840
00841 if ((print_downloads && s.state != torrent_status::seeding)
00842 || print_peers)
00843 h.get_peer_info(peers);
00844
00845 if (s.state != torrent_status::seeding)
00846 {
00847 char const* progress_bar_color = "33";
00848 if (s.state == torrent_status::checking_files
00849 || s.state == torrent_status::downloading_metadata)
00850 {
00851 progress_bar_color = "35";
00852 }
00853 else if (s.current_tracker.empty())
00854 {
00855 progress_bar_color = "31";
00856 }
00857 else if (sess_stat.has_incoming_connections)
00858 {
00859 progress_bar_color = "32";
00860 }
00861 out.precision(4);
00862 out.width(5);
00863 out.fill(' ');
00864 out << (s.progress*100) << "% ";
00865 out << progress_bar(s.progress, 49, progress_bar_color);
00866 out << "\n";
00867 out << " total downloaded: " << esc("32") << s.total_done << esc("0") << " Bytes ";
00868 out << "peers: " << s.num_peers << " "
00869 << "seeds: " << s.num_seeds << " "
00870 << "distributed copies: " << s.distributed_copies << "\n"
00871 << " download: " << esc("32") << (s.download_rate > 0 ? add_suffix(s.download_rate) + "/s ": " ") << esc("0")
00872 << "(" << esc("32") << add_suffix(s.total_download) << esc("0") << ") ";
00873 }
00874 else
00875 {
00876 out << "download: " << "(" << esc("32") << add_suffix(s.total_download) << esc("0") << ") ";
00877 }
00878 out << "upload: " << esc("31") << (s.upload_rate > 0 ? add_suffix(s.upload_rate) + "/s ": " ") << esc("0")
00879 << "(" << esc("31") << add_suffix(s.total_upload) << esc("0") << ") "
00880 << "ratio: " << ratio(s.total_payload_download, s.total_payload_upload) << "\n";
00881 if (s.state != torrent_status::seeding)
00882 {
00883 boost::posix_time::time_duration t = s.next_announce;
00884 out << " next announce: " << esc("37") <<
00885 boost::posix_time::to_simple_string(t) << esc("0") << " ";
00886 out << "tracker: " << s.current_tracker << "\n";
00887 }
00888
00889 if (print_peers && !peers.empty())
00890 print_peer_info(out, peers);
00891
00892 if (print_downloads && s.state != torrent_status::seeding)
00893 {
00894 h.get_download_queue(queue);
00895 for (std::vector<partial_piece_info>::iterator i = queue.begin();
00896 i != queue.end(); ++i)
00897 {
00898 out.width(4);
00899 out.fill(' ');
00900 out << i->piece_index << ": [";
00901 for (int j = 0; j < i->blocks_in_piece; ++j)
00902 {
00903 int index = peer_index(i->peer[j], peers);
00904 char str[] = "+";
00905 bool currently_downloading = false;
00906 if (index >= 0)
00907 {
00908 str[0] = (index < 10)?'0' + index:'A' + index - 10;
00909 currently_downloading = peers[index].downloading_piece_index == i->piece_index
00910 && peers[index].downloading_block_index == j;
00911 }
00912
00913 #ifdef ANSI_TERMINAL_COLORS
00914 if (currently_downloading)
00915 out << esc("33;7") << str << esc("0");
00916 else if (i->finished_blocks[j]) out << esc("32;7") << str << esc("0");
00917 else if (i->requested_blocks[j]) out << str;
00918 else out << "-";
00919 #else
00920 if (i->finished_blocks[j]) out << "#";
00921 else if (i->requested_blocks[j]) out << str;
00922 else out << "-";
00923 #endif
00924 }
00925 out << "]\n";
00926 }
00927
00928 out << "___________________________________\n";
00929 }
00930
00931 if (print_file_progress
00932 && s.state != torrent_status::seeding
00933 && h.has_metadata())
00934 {
00935 std::vector<float> file_progress;
00936 h.file_progress(file_progress);
00937 torrent_info const& info = h.get_torrent_info();
00938 for (int i = 0; i < info.num_files(); ++i)
00939 {
00940 if (file_progress[i] == 1.f)
00941 out << progress_bar(file_progress[i], 20, "32") << " "
00942 << info.file_at(i).path.leaf() << "\n";
00943 else
00944 out << progress_bar(file_progress[i], 20, "33") << " "
00945 << info.file_at(i).path.leaf() << "\n";
00946 }
00947
00948 out << "___________________________________\n";
00949 }
00950
00951 }
00952
00953 if (print_log)
00954 {
00955 for (std::deque<std::string>::iterator i = events.begin();
00956 i != events.end(); ++i)
00957 {
00958 out << *i << "\n";
00959 }
00960 }
00961
00962 clear_home();
00963 puts(out.str().c_str());
00964
00965 if (!monitor_dir.empty()
00966 && next_dir_scan < second_clock::universal_time())
00967 {
00968 scan_dir(monitor_dir, ses, handles, preferred_ratio
00969 , compact_allocation_mode, save_path);
00970 next_dir_scan = second_clock::universal_time() + seconds(poll_interval);
00971 }
00972 }
00973
00974 #ifndef TORRENT_DISABLE_DHT
00975 dht_state = ses.dht_state();
00976 boost::filesystem::ofstream out(".dht_state"
00977 , std::ios_base::binary);
00978 out.unsetf(std::ios_base::skipws);
00979 bencode(std::ostream_iterator<char>(out), dht_state);
00980 #endif
00981 }
00982 catch (std::exception& e)
00983 {
00984 std::cout << e.what() << "\n";
00985 }
00986
00987 #ifdef TORRENT_PROFILE
00988 print_checkpoints();
00989 #endif
00990 return 0;
00991 }
00992