From 7aacfca2923d7cfface6cf3f83d80b1f1b9d5141 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 26 Feb 2009 07:09:56 +0000 Subject: [PATCH] made the examples build without exception support. added overloads of add_torrent() and add_magnet_uri() that don't throw --- configure.in | 7 - docs/manual.rst | 19 + examples/Jamfile | 4 +- examples/Makefile.am | 2 +- examples/client_test.cpp | 1659 ++++++++++++--------------- examples/dump_torrent.cpp | 135 ++- examples/simple_client.cpp | 40 +- include/libtorrent/error_code.hpp | 1 + include/libtorrent/magnet_uri.hpp | 5 + include/libtorrent/torrent_info.hpp | 2 +- src/error_code.cpp | 1 + src/magnet_uri.cpp | 30 +- src/session.cpp | 2 + src/session_impl.cpp | 4 - 14 files changed, 894 insertions(+), 1017 deletions(-) diff --git a/configure.in b/configure.in index a77d45927..11e0f9dbd 100644 --- a/configure.in +++ b/configure.in @@ -147,13 +147,6 @@ if test -z "$BOOST_REGEX_LIB"; then BUILD_TESTCLIENT=no; fi -AX_BOOST_PROGRAM_OPTIONS -dnl check that Boost.Program_options was found: -if test -z "$BOOST_PROGRAM_OPTIONS_LIB"; then - AC_MSG_RESULT([Unable to find Boost.Program_options library, example test_client will not be build.]) - BUILD_TESTCLIENT=no; -fi - dnl Apply boost config. CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" diff --git a/docs/manual.rst b/docs/manual.rst index 0c887b3fb..ea86dd123 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -89,6 +89,9 @@ The ``session`` class has the following synopsis:: torrent_handle add_torrent( add_torrent_params const& params); + torrent_handle add_torrent( + add_torrent_params const& params + , error_code& ec); void pause(); void resume(); @@ -299,10 +302,15 @@ add_torrent() }; torrent_handle add_torrent(add_torrent_params const& params); + torrent_handle add_torrent(add_torrent_params const& params + , error_code& ec); You add torrents through the ``add_torrent()`` function where you give an object with all the parameters. +The overload that does not take an ``error_code`` throws an exception on +error and is not available when building without exception support. + The only mandatory parameter is ``save_path`` which is the directory where you want the files to be saved. You also need to specify either the ``ti`` (the torrent file) or ``info_hash`` (the info hash of the torrent). If you specify the @@ -4173,6 +4181,8 @@ add_magnet_uri() torrent_handle add_magnet_uri(session& ses, std::string const& uri add_torrent_params p); + torrent_handle add_magnet_uri(session& ses, std::string const& uri + add_torrent_params p, error_code& ec); This function parses the magnet URI (``uri``) as a bittorrent magnet link, and adds the torrent to the specified session (``ses``). It returns the @@ -4180,6 +4190,9 @@ handle to the newly added torrent, or an invalid handle in case parsing failed. To control some initial settings of the torrent, sepcify those in the ``add_torrent_params``, ``p``. See `add_torrent()`_. +The overload that does not take an ``error_code`` throws an exception on +error and is not available when building without exception support. + For more information about magnet links, see `magnet links`_. make_magnet_uri() @@ -5008,6 +5021,12 @@ code symbol description ------ ---------------------------- ----------------------------------------------------------------- 19 duplicate_torrent There's already a torrent with that info-hash added to the session +------ ---------------------------- ----------------------------------------------------------------- +20 invalid_torrent_handle The supplied torrent_handle is not referring to a valid torrent +------ ---------------------------- ----------------------------------------------------------------- +21 invalid_entry_type The type requested from the entry did not match its type +------ ---------------------------- ----------------------------------------------------------------- +22 missing_info_hash_in_uri The specified URI does not contain a valid info-hash ====== ============================ ================================================================= The names of these error codes are declared in then ``libtorrent::errors`` namespace. diff --git a/examples/Jamfile b/examples/Jamfile index 339569c97..4abba7feb 100644 --- a/examples/Jamfile +++ b/examples/Jamfile @@ -9,7 +9,6 @@ if $(BOOST_ROOT) use-project /boost : $(BOOST_ROOT) ; } -lib program-options : : boost_program_options ; lib regex : : boost_regex ; project client_test @@ -20,8 +19,7 @@ project client_test ; exe client_test : client_test.cpp - : /boost/program_options - /boost/regex + : /boost/regex ; exe simple_client : simple_client.cpp ; diff --git a/examples/Makefile.am b/examples/Makefile.am index 6c44e7a20..de2e808a7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -6,7 +6,7 @@ EXTRA_PROGRAMS = client_test dump_torrent make_torrent simple_client enum_if EXTRA_DIST = Jamfile client_test_SOURCES = client_test.cpp -client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la @BOOST_REGEX_LIB@ @BOOST_PROGRAM_OPTIONS_LIB@ +client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la @BOOST_REGEX_LIB@ dump_torrent_SOURCES = dump_torrent.cpp dump_torrent_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la diff --git a/examples/client_test.cpp b/examples/client_test.cpp index adf13bc11..60978770c 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -44,9 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include -#include #include #ifdef _MSC_VER @@ -349,8 +347,9 @@ void print_peer_info(std::ostream& out, std::vector const out.fill(' '); if (print_ip) { + error_code ec; std::stringstream ip; - ip << i->ip.address().to_string() << ":" << i->ip.port(); + ip << i->ip.address().to_string(ec) << ":" << i->ip.port(); out.width(22); out << ip.str() << " "; } @@ -496,13 +495,11 @@ void add_torrent(libtorrent::session& ses using namespace libtorrent; boost::intrusive_ptr t; - try + error_code ec; + t = new torrent_info(torrent.c_str(), ec); + if (ec) { - t = new torrent_info(torrent.c_str()); - } - catch (std::exception& e) - { - std::cout << torrent << ": " << e.what() << std::endl; + std::cout << torrent << ": " << ec.message() << std::endl; return; } @@ -523,7 +520,7 @@ void add_torrent(libtorrent::session& ses p.paused = true; p.duplicate_is_error = false; p.auto_managed = true; - torrent_handle h = ses.add_torrent(p); + torrent_handle h = ses.add_torrent(p, ec); handles.insert(std::make_pair( monitored_dir?std::string(torrent):std::string(), h)); @@ -672,965 +669,819 @@ static char const* state_str[] = {"checking (q)", "checking", "dl metadata" , "downloading", "finished", "seeding", "allocating", "checking (r)"}; -int main(int ac, char* av[]) +int main(int argc, char* argv[]) { #if BOOST_VERSION < 103400 using boost::filesystem::no_check; path::default_name_check(no_check); #endif - int listen_port; - float preferred_ratio; - int download_limit; - int upload_limit; - int torrent_upload_limit; - int torrent_download_limit; - int upload_slots_limit; - int half_open_limit; - std::string save_path_str; - std::string log_level; - std::string log_file_name; - std::string ip_filter_file; - std::string allocation_mode; - std::string in_monitor_dir; - std::string bind_to_interface; - std::string proxy; - std::string proxy_login; - std::string proxy_type; - int poll_interval; - int wait_retry; - int bind_port_start = 0; - int bind_port_end = 0; - - namespace po = boost::program_options; - try + if (argc == 1) { - - po::options_description desc("supported options"); - desc.add_options() - ("help,h", "display this help message") - ("port,p", po::value(&listen_port)->default_value(6881) - , "set listening port") - ("ratio,r", po::value(&preferred_ratio)->default_value(0) - , "set the preferred upload/download ratio. 0 means infinite. Values " - "smaller than 1 are clamped to 1.") - ("max-download-rate,d", po::value(&download_limit)->default_value(0) - , "the maximum download rate given in kB/s. 0 means infinite.") - ("max-upload-rate,u", po::value(&upload_limit)->default_value(0) - , "the maximum upload rate given in kB/s. 0 means infinite.") - ("max-torrent-upload-rate", po::value(&torrent_upload_limit)->default_value(20) - , "the maximum upload rate for an individual torrent, given in kB/s. 0 means infinite.") - ("max-torrent-download-rate", po::value(&torrent_download_limit)->default_value(0) - , "the maximum download rate for an individual torrent, given in kB/s. 0 means infinite.") - ("max-upload-slots", po::value(&upload_slots_limit)->default_value(5) - , "the maximum number of upload slots. 0 means infinite.") - ("save-path,s", po::value(&save_path_str)->default_value("./") - , "the path where the downloaded file/folder should be placed.") - ("log-level,l", po::value(&log_level)->default_value("info") - , "sets the level at which events are logged [debug | info | warning | fatal].") - ("log-file,f", po::value(&log_file_name)->default_value("") - , "sets a file to log all events to") - ("ip-filter,f", po::value(&ip_filter_file)->default_value("") - , "sets the path to the ip-filter file used to block access from certain " - "ips. ") - ("allocation-mode,a", po::value(&allocation_mode)->default_value("full") - , "sets mode used for allocating the downloaded files on disk. " - "Possible options are [full | compact]") - ("input-file,i", po::value >() - , "adds an input .torrent file. At least one is required. arguments " - "without any flag are implicitly an input file. To start a torrentless " - "download, use @ instead of specifying a file.") - ("monitor-dir,m", po::value(&in_monitor_dir) - , "monitors the given directory, looking for .torrent files and " - "automatically starts downloading them. It will stop downloading " - "torrent files that are removed from the directory") - ("poll-interval,t", po::value(&poll_interval)->default_value(2) - , "if a directory is being monitored, this is the interval (given " - "in seconds) between two refreshes of the directory listing") - ("wait-retry,w", po::value(&wait_retry)->default_value(30) - , "if the download of a url seed failes, this is the interval (given " - "in seconds) to wait until the next retry") - ("half-open-limit,o", po::value(&half_open_limit)->default_value(-1) - , "Sets the maximum number of simultaneous half-open tcp connections") - ("bind,b", po::value(&bind_to_interface)->default_value("") - , "Sets the local interface to bind outbound and the listen " - "socket to") - ("proxy-server,x", po::value(&proxy)->default_value("") - , "Sets the http proxy to be used for tracker and web seeds " - "connections. The string is expected to be on the form: " - ":. If no port is specified, 8080 is assumed") - ("proxy-login,n", po::value(&proxy_login)->default_value("") - , "Sets the username and password used to authenticate with the http " - "proxy. The string should be given in the form: :") - ("proxy-type", po::value(&proxy_type)->default_value("socks5") - , "Sets the type of proxy to use [socks5 | http] ") - ("bind-port-start", po::value(&bind_port_start)->default_value(0) - , "The lower port number that outgoing connections will be bound to") - ("bind-port-end", po::value(&bind_port_end)->default_value(0) - , "The upper port number that outgoing connections will be bound to") + std::cerr << "usage: client_test [OPTIONS] [TORRENT|MAGNETURL]\n\n" + "OPTIONS:\n" + " -f logs all events to the given file\n" + " -o limits the number of simultaneous\n" + " half-open TCP connections to the\n" + " given number.\n" + " -p sets the listen port\n" + " -r sets the preferred share ratio\n" + " -d limits the download rate\n" + " -u limits the upload rate\n" + " -S limits the upload slots\n" + " -a sets the allocation mode. [compact|full]\n" + " -s sets the save path for downloads\n" + " -U sets per-torrent upload rate\n" + " -D sets per-torrent download rate\n" + " -m sets the .torrent monitor directory\n" + " -b sets IP of the interface to bind the\n" + " listen socket to\n" + " -w sets the retry time for failed web seeds\n" + " -t sets the scan interval of the monitor dir\n" + " -x loads an emule IP-filter file\n" + " -c sets the max number of connections\n" + "\n\n" + "TORRENT is a path to a .torrent file\n" + "MAGNETURL is a magnet: url\n" ; + return 0; + } - po::positional_options_description p; - p.add("input-file", -1); + using namespace libtorrent; + session_settings settings; + proxy_settings ps; - po::variables_map vm; - po::store(po::command_line_parser(ac, av). - options(desc).positional(p).run(), vm); - po::notify(vm); + settings.user_agent = "client_test/" LIBTORRENT_VERSION; + settings.announce_to_all_trackers = true; - // make sure the arguments stays within the usable limits - path monitor_dir(in_monitor_dir); - if (listen_port < 0 || listen_port > 65525) listen_port = 6881; - if (preferred_ratio != 0 && preferred_ratio < 1.f) preferred_ratio = 1.f; - upload_limit *= 1000; - torrent_upload_limit *= 1000; - torrent_download_limit *= 1000; - download_limit *= 1000; - if (download_limit <= 0) download_limit = -1; - if (upload_limit <= 0) upload_limit = -1; - if (torrent_upload_limit <= 0) torrent_upload_limit = -1; - if (torrent_download_limit <= 0) torrent_download_limit = -1; - if (poll_interval < 2) poll_interval = 2; - if (wait_retry < 0) wait_retry = 0; - if (half_open_limit < 1) half_open_limit = -1; - if (upload_slots_limit <= 0) upload_slots_limit = -1; - if (!monitor_dir.empty() && !exists(monitor_dir)) - { - std::cerr << "The monitor directory doesn't exist: " << monitor_dir.string() << std::endl; - return 1; - } + std::deque events; - if (vm.count("help") - || vm.count("input-file") + vm.count("monitor-dir") == 0) - { - std::cout << desc << "\n"; - return 1; - } + ptime next_dir_scan = time_now(); - if (!log_file_name.empty()) - g_log_file.open(log_file_name.c_str()); + // the string is the filename of the .torrent file, but only if + // it was added through the directory monitor. It is used to + // be able to remove torrents that were added via the directory + // monitor when they're not in the directory anymore. + handles_t handles; + session ses(fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) + , session::start_default_features | session::add_default_plugins, alert::all_categories); - bool compact_allocation_mode = (allocation_mode == "compact"); - - using namespace libtorrent; - - std::vector input; - if (vm.count("input-file") > 0) - input = vm["input-file"].as< std::vector >(); - - session_settings settings; - proxy_settings ps; - - if (!proxy.empty()) - { - std::size_t i = proxy.find(':'); - ps.hostname = proxy.substr(0, i); - if (i == std::string::npos) ps.port = 8080; - else ps.port = atoi(proxy.substr(i + 1).c_str()); - if (proxy_type == "socks5") - ps.type = proxy_settings::socks5; - else - ps.type = proxy_settings::http; - - if (!proxy_login.empty()) - { - std::size_t i = proxy_login.find(':'); - if (i == std::string::npos) - { - std::cerr << "Proxy login did not match the required format: " - << proxy_login << std::endl; - return 1; - } - ps.username = proxy_login.substr(0, i); - ps.password = proxy_login.substr(i + 1); - if (proxy_type == "socks5") - ps.type = proxy_settings::socks5_pw; - else - ps.type = proxy_settings::http_pw; - } - } - - settings.user_agent = "client_test/" LIBTORRENT_VERSION; - settings.urlseed_wait_retry = wait_retry; - settings.announce_to_all_trackers = true; - - settings.outgoing_ports.first = bind_port_start; - settings.outgoing_ports.second = bind_port_end; - - std::deque events; - - ptime next_dir_scan = time_now(); - - // the string is the filename of the .torrent file, but only if - // it was added through the directory monitor. It is used to - // be able to remove torrents that were added via the directory - // monitor when they're not in the directory anymore. - handles_t handles; - session ses(fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) - , session::start_default_features | session::add_default_plugins, alert::all_categories); -#ifndef TORRENT_DISABLE_GEO_IP - ses.load_asnum_db("GeoIPASNum.dat"); - ses.load_country_db("GeoIP.dat"); -#endif - // UPnP port mapping - ses.start_upnp(); - // NAT-PMP port mapping - ses.start_natpmp(); - // Local service discovery (finds peers on the local network) - ses.start_lsd(); - ses.add_extension(&create_metadata_plugin); - ses.add_extension(&create_ut_pex_plugin); - ses.add_extension(&create_ut_metadata_plugin); - ses.add_extension(&create_smart_ban_plugin); - - ses.set_max_uploads(upload_slots_limit); - ses.set_max_half_open_connections(half_open_limit); - ses.set_download_rate_limit(download_limit); - ses.set_upload_rate_limit(upload_limit); - ses.listen_on(std::make_pair(listen_port, listen_port + 10) - , bind_to_interface.c_str()); - ses.set_settings(settings); - ses.set_tracker_proxy(ps); - ses.set_peer_proxy(ps); - ses.set_web_seed_proxy(ps); - -#ifndef TORRENT_NO_DEPRECATE - if (log_level == "debug") - ses.set_severity_level(alert::debug); - else if (log_level == "warning") - ses.set_severity_level(alert::warning); - else if (log_level == "fatal") - ses.set_severity_level(alert::fatal); - else - ses.set_severity_level(alert::info); -#endif - - boost::filesystem::ifstream ses_state_file(".ses_state" - , std::ios_base::binary); - ses_state_file.unsetf(std::ios_base::skipws); - ses.load_state(bdecode( - std::istream_iterator(ses_state_file) - , std::istream_iterator())); + boost::filesystem::ifstream ses_state_file(".ses_state" + , std::ios_base::binary); + ses_state_file.unsetf(std::ios_base::skipws); + ses.load_state(bdecode( + std::istream_iterator(ses_state_file) + , std::istream_iterator())); #ifndef TORRENT_DISABLE_DHT - settings.use_dht_as_fallback = false; + settings.use_dht_as_fallback = false; - ses.add_dht_router(std::make_pair( + ses.add_dht_router(std::make_pair( std::string("router.bittorrent.com"), 6881)); - ses.add_dht_router(std::make_pair( + ses.add_dht_router(std::make_pair( std::string("router.utorrent.com"), 6881)); - ses.add_dht_router(std::make_pair( + ses.add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); - boost::filesystem::ifstream dht_state_file(".dht_state" - , std::ios_base::binary); - dht_state_file.unsetf(std::ios_base::skipws); - entry dht_state; - dht_state = bdecode( - std::istream_iterator(dht_state_file) - , std::istream_iterator()); - ses.start_dht(dht_state); + boost::filesystem::ifstream dht_state_file(".dht_state" + , std::ios_base::binary); + dht_state_file.unsetf(std::ios_base::skipws); + entry dht_state; + dht_state = bdecode( + std::istream_iterator(dht_state_file) + , std::istream_iterator()); + ses.start_dht(dht_state); #endif - // look for ipfilter.dat - // poor man's parser - // reads emule ipfilter files. - // with the following format: - // - // - , , - // - // first-ip is an ip address that defines the first - // address of the range - // last-ip is the last ip address in the range - // access is a number specifying the access control - // for this ip-range. Right now values > 127 = allowed - // and numbers <= 127 = blocked - // the rest of the line is ignored - // - // In the original spec ranges may not overlap, but - // here ranges may overlap, and it is the last added - // rule that has precedence for addresses that may fall - // into more than one range. - if (!ip_filter_file.empty()) - { - std::ifstream in(ip_filter_file.c_str()); - ip_filter filter; - while (in.good()) - { - char line[300]; - in.getline(line, 300); - int len = in.gcount(); - if (len <= 0) continue; - if (line[0] == '#') continue; - int a, b, c, d; - char dummy; - std::stringstream ln(line); - ln >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy; - address_v4 start((a << 24) + (b << 16) + (c << 8) + d); - ln >> a >> dummy >> b >> dummy >> c >> dummy >> d; - address_v4 last((a << 24) + (b << 16) + (c << 8) + d); - int flags; - ln >> flags; - if (flags <= 127) flags = ip_filter::blocked; - else flags = 0; - if (ln.fail()) break; - filter.add_rule(start, last, flags); - } - ses.set_ip_filter(filter); - } - boost::filesystem::path save_path(save_path_str); - - // load the torrents given on the commandline - boost::regex ex("([0-9A-Fa-f]{40})@(.+)"); - for (std::vector::const_iterator i = input.begin(); - i != input.end(); ++i) - { -#ifndef BOOST_NO_EXCEPTIONS - try - { -#endif - // first see if this is a torrentless download - if (i->substr(0, 7) == "magnet:") - { - add_torrent_params p; - p.save_path = save_path; - p.storage_mode = compact_allocation_mode ? storage_mode_compact - : storage_mode_sparse; - std::cout << "adding MANGET link: " << *i << std::endl; - torrent_handle h = add_magnet_uri(ses, *i, p); - - handles.insert(std::make_pair(std::string(), h)); - - h.set_max_connections(50); - h.set_max_uploads(-1); - h.set_ratio(preferred_ratio); - h.set_upload_limit(torrent_upload_limit); - h.set_download_limit(torrent_download_limit); - continue; - } - boost::cmatch what; - if (boost::regex_match(i->c_str(), what, ex)) - { - sha1_hash info_hash = boost::lexical_cast(what[1]); - - add_torrent_params p; - p.name = std::string(what[2]).c_str(); - p.info_hash = info_hash; - p.save_path = save_path; - p.storage_mode = compact_allocation_mode ? storage_mode_compact : storage_mode_sparse; - p.paused = true; - p.duplicate_is_error = false; - p.auto_managed = true; - torrent_handle h = ses.add_torrent(p); - - handles.insert(std::make_pair(std::string(), h)); - - h.set_max_connections(50); - h.set_max_uploads(-1); - h.set_ratio(preferred_ratio); - h.set_upload_limit(torrent_upload_limit); - h.set_download_limit(torrent_download_limit); - continue; - } - // if it's a torrent file, open it as usual - add_torrent(ses, handles, i->c_str(), preferred_ratio - , compact_allocation_mode, save_path, false - , torrent_upload_limit, torrent_download_limit); -#ifndef BOOST_NO_EXCEPTIONS - } - catch (std::exception& e) - { - std::cout << e.what() << "\n"; - } -#endif - } - - // main loop - std::vector peers; - std::vector queue; - - for (;;) - { - char c; - while (sleep_and_input(&c)) - { - if (c == 27) - { - // escape code, read another character -#ifdef _WIN32 - c = _getch(); -#else - c = getc(stdin); -#endif - if (c != '[') break; -#ifdef _WIN32 - c = _getch(); -#else - c = getc(stdin); -#endif - if (c == 65) - { - // arrow up - --active_torrent; - if (active_torrent < 0) active_torrent = 0; - } - else if (c == 66) - { - // arrow down - ++active_torrent; - if (active_torrent >= handles.size()) active_torrent = handles.size() - 1; - } - } - - if (c == ' ') - { - if (ses.is_paused()) ses.resume(); - else ses.pause(); - } - - if (c == 'm') - { - std::cout << "saving peers for torrents" << std::endl; - - std::vector peers; - for (handles_t::iterator i = handles.begin(); - i != handles.end(); ++i) - { - i->second.get_full_peer_list(peers); - std::ofstream f(("peers_" + i->second.name()).c_str()); - for (std::vector::iterator k = peers.begin() - , end(peers.end()); k != end; ++k) - { - f << k->ip.address() #ifndef TORRENT_DISABLE_GEO_IP - << "\t" << ses.as_for_ip(k->ip.address()) + ses.load_asnum_db("GeoIPASNum.dat"); + ses.load_country_db("GeoIP.dat"); #endif - << std::endl; - } - } - } - if (c == 'q') + int listen_port = 6881; + float preferred_ratio = 0.f; + std::string allocation_mode = "sparse"; + boost::filesystem::path save_path("."); + int torrent_upload_limit = 0; + int torrent_download_limit = 0; + boost::filesystem::path monitor_dir; + std::string bind_to_interface = ""; + int poll_interval = 5; + + // load the torrents given on the commandline + boost::regex ex("([0-9A-Fa-f]{40})@(.+)"); + + for (int i = 1; i < argc; ++i) + { + if (argv[i][0] != '-') + { + // interpret this as a torrent + + // first see if this is a torrentless download + if (std::strstr("magnet:", argv[i]) == argv[i]) + { + add_torrent_params p; + p.save_path = save_path; + p.storage_mode = allocation_mode == "compact" ? storage_mode_compact + : storage_mode_sparse; + std::cout << "adding MANGET link: " << argv[i] << std::endl; + error_code ec; + torrent_handle h = add_magnet_uri(ses, argv[i], p, ec); + if (ec) { - // keep track of the number of resume data - // alerts to wait for - int num_resume_data = 0; - ses.pause(); - for (handles_t::iterator i = handles.begin(); - i != handles.end(); ++i) - { - torrent_handle& h = i->second; - if (!h.is_valid()) continue; - if (h.is_paused()) continue; - if (!h.has_metadata()) continue; - - std::cout << "saving resume data for " << h.name() << std::endl; - // save_resume_data will generate an alert when it's done - h.save_resume_data(); - ++num_resume_data; - } - std::cout << "waiting for resume data" << std::endl; - - while (num_resume_data > 0) - { - alert const* a = ses.wait_for_alert(seconds(30)); - if (a == 0) - { - std::cout << " aborting with " << num_resume_data << " outstanding " - "torrents to save resume data for" << std::endl; - break; - } - - std::auto_ptr holder = ses.pop_alert(); - - ::print_alert(holder.get(), std::cout); - std::cout << std::endl; - - if (dynamic_cast(a)) - { - --num_resume_data; - continue; - } - - save_resume_data_alert const* rd = dynamic_cast(a); - if (!rd) continue; - --num_resume_data; - - if (!rd->resume_data) continue; - - torrent_handle h = rd->handle; - boost::filesystem::ofstream out(h.save_path() - / (h.get_torrent_info().name() + ".fastresume"), std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), *rd->resume_data); - } - break; + std::cerr << ec.message() << std::endl; + continue; } - if (c == 'j') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) h.force_recheck(); - } + handles.insert(std::make_pair(std::string(), h)); - if (c == 'r') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) h.force_reannounce(); - } - - if (c == 's') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) h.set_sequential_download(!h.is_sequential_download()); - } - - if (c == 'v') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) h.scrape_tracker(); - } - - if (c == 'p') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) - { - if (!h.is_auto_managed() && h.is_paused()) - { - h.auto_managed(true); - } - else - { - h.auto_managed(false); - h.pause(); - } - // the alert handler for save_resume_data_alert - // will save it to disk - h.save_resume_data(); - } - } - - if (c == 'c') - { - torrent_handle h = get_active_torrent(handles); - if (h.is_valid()) h.clear_error(); - } - - // toggle displays - if (c == 't') print_trackers = !print_trackers; - if (c == 'i') print_peers = !print_peers; - if (c == 'l') print_log = !print_log; - if (c == 'd') print_downloads = !print_downloads; - if (c == 'f') print_file_progress = !print_file_progress; - if (c == 'h') show_pad_files = !show_pad_files; - if (c == 'a') print_piece_bar = !print_piece_bar; - if (c == 'g') show_dht_status = !show_dht_status; - // toggle columns - if (c == '1') print_ip = !print_ip; - if (c == '2') print_as = !print_as; - if (c == '3') print_timers = !print_timers; - if (c == '4') print_block = !print_block; - if (c == '5') print_peer_rate = !print_peer_rate; - if (c == '6') print_fails = !print_fails; - if (c == '7') print_send_bufs = !print_send_bufs; + h.set_max_connections(50); + h.set_max_uploads(-1); + h.set_ratio(preferred_ratio); + h.set_upload_limit(torrent_upload_limit); + h.set_download_limit(torrent_download_limit); + continue; } - if (c == 'q') break; - int terminal_width = 80; + // match it against the @ format + boost::cmatch what; + if (boost::regex_match(argv[i], what, ex)) + { + sha1_hash info_hash = boost::lexical_cast(what[1]); + + add_torrent_params p; + p.name = std::string(what[2]).c_str(); + p.info_hash = info_hash; + p.save_path = save_path; + p.storage_mode = allocation_mode == "compact" ? storage_mode_compact + : storage_mode_sparse; + p.paused = true; + p.duplicate_is_error = false; + p.auto_managed = true; + error_code ec; + torrent_handle h = ses.add_torrent(p, ec); + if (ec) + { + std::cerr << ec.message() << std::endl; + continue; + } + + handles.insert(std::make_pair(std::string(), h)); + + h.set_max_connections(50); + h.set_max_uploads(-1); + h.set_ratio(preferred_ratio); + h.set_upload_limit(torrent_upload_limit); + h.set_download_limit(torrent_download_limit); + continue; + } + + // if it's a torrent file, open it as usual + add_torrent(ses, handles, argv[i], preferred_ratio + , allocation_mode == "compact", save_path, false + , torrent_upload_limit, torrent_download_limit); + continue; + } + + // if there's a flag but no argument following, ignore it + if (argc == i) continue; + char const* arg = argv[i+1]; + switch (argv[i][1]) + { + case 'f': g_log_file.open(arg); break; + case 'o': ses.set_max_half_open_connections(atoi(arg)); break; + case 'p': listen_port = atoi(arg); break; + case 'r': + preferred_ratio = atoi(arg); + if (preferred_ratio != 0 && preferred_ratio < 1.f) preferred_ratio = 1.f; + break; + case 'd': ses.set_download_rate_limit(atoi(arg) * 1000); break; + case 'u': ses.set_upload_rate_limit(atoi(arg) * 1000); break; + case 'S': ses.set_max_uploads(atoi(arg)); break; + case 'a': allocation_mode = arg; break; + case 's': save_path = arg; break; + case 'U': torrent_upload_limit = atoi(arg) * 1000; break; + case 'D': torrent_download_limit = atoi(arg) * 1000; break; + case 'm': monitor_dir = arg; break; + case 'b': bind_to_interface = arg; break; + case 'w': settings.urlseed_wait_retry = atoi(arg); break; + case 't': poll_interval = atoi(arg); break; + case 'x': + { + std::ifstream in(arg); + ip_filter filter; + while (in.good()) + { + char line[300]; + in.getline(line, 300); + int len = in.gcount(); + if (len <= 0) continue; + if (line[0] == '#') continue; + int a, b, c, d; + char dummy; + std::stringstream ln(line); + ln >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy; + address_v4 start((a << 24) + (b << 16) + (c << 8) + d); + ln >> a >> dummy >> b >> dummy >> c >> dummy >> d; + address_v4 last((a << 24) + (b << 16) + (c << 8) + d); + int flags; + ln >> flags; + if (flags <= 127) flags = ip_filter::blocked; + else flags = 0; + if (ln.fail()) break; + filter.add_rule(start, last, flags); + } + ses.set_ip_filter(filter); + } + break; + case 'c': ses.set_max_connections(atoi(arg)); break; + } + } + + ses.listen_on(std::make_pair(listen_port, listen_port + 10) + , bind_to_interface.c_str()); + + ses.set_settings(settings); + + // main loop + std::vector peers; + std::vector queue; + + for (;;) + { + char c; + while (sleep_and_input(&c)) + { + if (c == 27) + { + // escape code, read another character +#ifdef _WIN32 + c = _getch(); +#else + c = getc(stdin); +#endif + if (c != '[') break; +#ifdef _WIN32 + c = _getch(); +#else + c = getc(stdin); +#endif + if (c == 65) + { + // arrow up + --active_torrent; + if (active_torrent < 0) active_torrent = 0; + } + else if (c == 66) + { + // arrow down + ++active_torrent; + if (active_torrent >= handles.size()) active_torrent = handles.size() - 1; + } + } + + if (c == ' ') + { + if (ses.is_paused()) ses.resume(); + else ses.pause(); + } + + if (c == 'm') + { + std::cout << "saving peers for torrents" << std::endl; + + std::vector peers; + for (handles_t::iterator i = handles.begin(); + i != handles.end(); ++i) + { + i->second.get_full_peer_list(peers); + std::ofstream f(("peers_" + i->second.name()).c_str()); + for (std::vector::iterator k = peers.begin() + , end(peers.end()); k != end; ++k) + { + f << k->ip.address() +#ifndef TORRENT_DISABLE_GEO_IP + << "\t" << ses.as_for_ip(k->ip.address()) +#endif + << std::endl; + } + } + } + + if (c == 'q') + { + // keep track of the number of resume data + // alerts to wait for + int num_resume_data = 0; + ses.pause(); + for (handles_t::iterator i = handles.begin(); + i != handles.end(); ++i) + { + torrent_handle& h = i->second; + if (!h.is_valid()) continue; + if (h.is_paused()) continue; + if (!h.has_metadata()) continue; + + std::cout << "saving resume data for " << h.name() << std::endl; + // save_resume_data will generate an alert when it's done + h.save_resume_data(); + ++num_resume_data; + } + std::cout << "waiting for resume data" << std::endl; + + while (num_resume_data > 0) + { + alert const* a = ses.wait_for_alert(seconds(30)); + if (a == 0) + { + std::cout << " aborting with " << num_resume_data << " outstanding " + "torrents to save resume data for" << std::endl; + break; + } + + std::auto_ptr holder = ses.pop_alert(); + + ::print_alert(holder.get(), std::cout); + std::cout << std::endl; + + if (dynamic_cast(a)) + { + --num_resume_data; + continue; + } + + save_resume_data_alert const* rd = dynamic_cast(a); + if (!rd) continue; + --num_resume_data; + + if (!rd->resume_data) continue; + + torrent_handle h = rd->handle; + boost::filesystem::ofstream out(h.save_path() + / (h.get_torrent_info().name() + ".fastresume"), std::ios_base::binary); + out.unsetf(std::ios_base::skipws); + bencode(std::ostream_iterator(out), *rd->resume_data); + } + break; + } + + if (c == 'j') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) h.force_recheck(); + } + + if (c == 'r') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) h.force_reannounce(); + } + + if (c == 's') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) h.set_sequential_download(!h.is_sequential_download()); + } + + if (c == 'v') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) h.scrape_tracker(); + } + + if (c == 'p') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) + { + if (!h.is_auto_managed() && h.is_paused()) + { + h.auto_managed(true); + } + else + { + h.auto_managed(false); + h.pause(); + } + // the alert handler for save_resume_data_alert + // will save it to disk + h.save_resume_data(); + } + } + + if (c == 'c') + { + torrent_handle h = get_active_torrent(handles); + if (h.is_valid()) h.clear_error(); + } + + // toggle displays + if (c == 't') print_trackers = !print_trackers; + if (c == 'i') print_peers = !print_peers; + if (c == 'l') print_log = !print_log; + if (c == 'd') print_downloads = !print_downloads; + if (c == 'f') print_file_progress = !print_file_progress; + if (c == 'h') show_pad_files = !show_pad_files; + if (c == 'a') print_piece_bar = !print_piece_bar; + if (c == 'g') show_dht_status = !show_dht_status; + // toggle columns + if (c == '1') print_ip = !print_ip; + if (c == '2') print_as = !print_as; + if (c == '3') print_timers = !print_timers; + if (c == '4') print_block = !print_block; + if (c == '5') print_peer_rate = !print_peer_rate; + if (c == '6') print_fails = !print_fails; + if (c == '7') print_send_bufs = !print_send_bufs; + } + if (c == 'q') break; + + int terminal_width = 80; #ifndef _WIN32 - { - winsize size; - ioctl(STDOUT_FILENO, TIOCGWINSZ, (char*)&size); - terminal_width = size.ws_col; - } + { + winsize size; + ioctl(STDOUT_FILENO, TIOCGWINSZ, (char*)&size); + terminal_width = size.ws_col; + } #endif - // loop through the alert queue to see if anything has happened. - std::auto_ptr a; + // loop through the alert queue to see if anything has happened. + std::auto_ptr a; + a = ses.pop_alert(); + std::string now = time_now_string(); + while (a.get()) + { + std::stringstream event_string; + + ::print_alert(a.get(), event_string); + ::handle_alert(ses, a.get(), handles); + + events.push_back(event_string.str()); + if (events.size() >= 20) events.pop_front(); + a = ses.pop_alert(); - std::string now = time_now_string(); - while (a.get()) + } + + session_status sess_stat = ses.status(); + + std::stringstream out; + out << "[q] quit [i] toggle peers [d] toggle downloading pieces [p] toggle paused " + "[a] toggle piece bar [s] toggle download sequential [f] toggle files " + "[j] force recheck [space] toggle session pause [c] clear error [v] scrape [g] show DHT\n" + "[1] toggle IP [2] toggle AS [3] toggle timers [4] toggle block progress " + "[5] toggle peer rate [6] toggle failures [7] toggle send buffers\n"; + + int torrent_index = 0; + torrent_handle active_handle; + for (handles_t::iterator i = handles.begin(); + i != handles.end(); ++torrent_index) + { + torrent_handle& h = i->second; + if (!h.is_valid()) { - std::stringstream event_string; - - ::print_alert(a.get(), event_string); - ::handle_alert(ses, a.get(), handles); - - events.push_back(event_string.str()); - if (events.size() >= 20) events.pop_front(); - - a = ses.pop_alert(); + handles.erase(i++); + continue; } - - session_status sess_stat = ses.status(); - - std::stringstream out; - out << "[q] quit [i] toggle peers [d] toggle downloading pieces [p] toggle paused " - "[a] toggle piece bar [s] toggle download sequential [f] toggle files " - "[j] force recheck [space] toggle session pause [c] clear error [v] scrape [g] show DHT\n" - "[1] toggle IP [2] toggle AS [3] toggle timers [4] toggle block progress " - "[5] toggle peer rate [6] toggle failures [7] toggle send buffers\n"; - - int torrent_index = 0; - torrent_handle active_handle; - for (handles_t::iterator i = handles.begin(); - i != handles.end(); ++torrent_index) + else { - torrent_handle& h = i->second; - if (!h.is_valid()) - { - handles.erase(i++); - continue; - } - else - { - ++i; - } + ++i; + } #ifdef ANSI_TERMINAL_COLORS - char const* term = "\x1b[0m"; + char const* term = "\x1b[0m"; #else - char const* term = ""; + char const* term = ""; #endif - if (active_torrent == torrent_index) - { - term = "\x1b[0m\x1b[7m"; - out << esc("7") << "*"; - } - else - { - out << " "; - } - - int queue_pos = h.queue_position(); - if (queue_pos == -1) out << "- "; - else out << std::setw(3) << queue_pos; - - if (h.is_paused()) out << esc("34"); - else out << esc("37"); - out << std::setw(40) << std::setiosflags(std::ios::left); - - std::string name = h.name(); - if (name.size() > 40) name.resize(40); - out << name; - - out << term << " "; - - torrent_status s = h.status(); - - bool paused = h.is_paused(); - bool auto_managed = h.is_auto_managed(); - bool sequential_download = h.is_sequential_download(); - out << std::setw(13) << std::setiosflags(std::ios::left); - if (!s.error.empty()) - { - out << esc("31") << "error " << s.error; - out << esc("0") << std::endl; - continue; - } - - if (paused && !auto_managed) out << "paused"; - else if (paused && auto_managed) out << "queued"; - else out << state_str[s.state]; - - int seeds = 0; - int downloaders = 0; - - if (s.num_complete >= 0) seeds = s.num_complete; - else seeds = s.list_seeds; - - if (s.num_incomplete >= 0) downloaders = s.num_incomplete; - else downloaders = s.list_peers - s.list_seeds; - - out << "download: " << "(" << esc("32") << add_suffix(s.total_download) << term << ") " - "upload: " << esc("31") << (s.upload_rate > 0 ? add_suffix(s.upload_rate) + "/s ": " ") << term - << "(" << esc("31") << add_suffix(s.total_upload) << term << ") " - << "swarm: " << to_string(downloaders, 4) << ":" << to_string(seeds, 4) - << " bw queue: (" << s.up_bandwidth_queue << " | " << s.down_bandwidth_queue << ") " - "all-time (Rx: " << esc("32") << add_suffix(s.all_time_download) << term - << " Tx: " << esc("31") << add_suffix(s.all_time_upload) << term << ") " - << std::hex << s.seed_rank << std::dec << " " - << s.last_scrape << "\n" << esc("0"); - - if (torrent_index != active_torrent && s.state == torrent_status::seeding) continue; - char const* progress_bar_color = "33"; // yellow - if (s.state == torrent_status::checking_files - || s.state == torrent_status::downloading_metadata) - { - progress_bar_color = "35"; // magenta - } - else if (s.current_tracker.empty()) - { - progress_bar_color = "31"; // red - } - else if (sess_stat.has_incoming_connections) - { - progress_bar_color = "32"; // green - } - if (sequential_download) - out << "sequential: "; - else - out << " progress: "; - - out << esc("32") << s.total_done << esc("0") << " Bytes "; - out.precision(4); - out.width(5); - out.fill(' '); - out << (s.progress*100) << "% "; - out << progress_bar(s.progress, terminal_width - 37, progress_bar_color) << "\n"; - if (print_piece_bar && s.progress < 1.f) - out << " " << piece_bar(s.pieces, terminal_width - 5) << "\n"; - out << " peers: " << esc("37") << s.num_peers << esc("0") << " (" << esc("37") << s.connect_candidates << esc("0") << ") " - << "seeds: " << esc("37") << s.num_seeds << esc("0") << " " - << "distributed copies: " << esc("37") << s.distributed_copies << esc("0") - << " sparse regions: " << s.sparse_regions -// << " magnet-link: " << make_magnet_uri(h) << "\n" - << " download: " << esc("32") << (s.download_rate > 0 ? add_suffix(s.download_rate) + "/s ": " ") << esc("0"); - boost::posix_time::time_duration t = s.next_announce; - out << " next announce: " << esc("37") - << to_string(t.hours(), 2) << ":" - << to_string(t.minutes(), 2) << ":" - << to_string(t.seconds(), 2) << esc("0") << " "; - out << "tracker: " << esc("36") << s.current_tracker << esc("0") << "\n"; - - if (torrent_index != active_torrent) continue; - active_handle = h; + if (active_torrent == torrent_index) + { + term = "\x1b[0m\x1b[7m"; + out << esc("7") << "*"; + } + else + { + out << " "; } - cache_status cs = ses.get_cache_status(); - if (cs.blocks_read < 1) cs.blocks_read = 1; - if (cs.blocks_written < 1) cs.blocks_written = 1; + int queue_pos = h.queue_position(); + if (queue_pos == -1) out << "- "; + else out << std::setw(3) << queue_pos; - out << "==== conns: " << sess_stat.num_peers - << " down: " << esc("32") << add_suffix(sess_stat.download_rate) << "/s" << esc("0") - << " (" << esc("32") << add_suffix(sess_stat.total_download) << esc("0") << ")" - " up: " << esc("31") << add_suffix(sess_stat.upload_rate) << "/s" << esc("0") - << " (" << esc("31") << add_suffix(sess_stat.total_upload) << esc("0") << ")" - " tcp/ip: " - << esc("32") << add_suffix(sess_stat.ip_overhead_download_rate) << "/s" << esc("0") << " " - << esc("31") << add_suffix(sess_stat.ip_overhead_upload_rate) << "/s" << esc("0") - << " DHT: " - << esc("32") << add_suffix(sess_stat.dht_download_rate) << "/s" << esc("0") << " " - << esc("31") << add_suffix(sess_stat.dht_upload_rate) << "/s" << esc("0") - << " tracker: " - << esc("32") << add_suffix(sess_stat.tracker_download_rate) << "/s" << esc("0") << " " - << esc("31") << add_suffix(sess_stat.tracker_upload_rate) << "/s" << esc("0") << " ====\n" - "==== waste: " << add_suffix(sess_stat.total_redundant_bytes) - << " fail: " << add_suffix(sess_stat.total_failed_bytes) - << " unchoked: " << sess_stat.num_unchoked << " / " << sess_stat.allowed_upload_slots - << " bw queues: " << sess_stat.up_bandwidth_bytes_queue - << " (" << sess_stat.up_bandwidth_queue<< ")" - << " | " << sess_stat.down_bandwidth_bytes_queue - << " (" << sess_stat.down_bandwidth_queue<< ") " - " write cache hits: " << ((cs.blocks_written - cs.writes) * 100 / cs.blocks_written) << "% " - " read cache hits: " << (cs.blocks_read_hit * 100 / cs.blocks_read) << "% " - " cache size: " << add_suffix(cs.cache_size * 16 * 1024) - << " (" << add_suffix(cs.read_cache_size * 16 * 1024) << ")" - " ====\n" - "==== optimistic unchoke: " << sess_stat.optimistic_unchoke_counter - << " unchoke counter: " << sess_stat.unchoke_counter - << " ====" << std::endl; + if (h.is_paused()) out << esc("34"); + else out << esc("37"); + out << std::setw(40) << std::setiosflags(std::ios::left); - if (show_dht_status) + std::string name = h.name(); + if (name.size() > 40) name.resize(40); + out << name; + + out << term << " "; + + torrent_status s = h.status(); + + bool paused = h.is_paused(); + bool auto_managed = h.is_auto_managed(); + bool sequential_download = h.is_sequential_download(); + out << std::setw(13) << std::setiosflags(std::ios::left); + if (!s.error.empty()) { - out << "DHT nodes: " << sess_stat.dht_nodes - << " DHT cached nodes: " << sess_stat.dht_node_cache - << " total DHT size: " << sess_stat.dht_global_nodes << std::endl; - for (std::vector::iterator i = sess_stat.active_requests.begin() - , end(sess_stat.active_requests.end()); i != end; ++i) - { - out << " " << i->type << " " << i->outstanding_requests << " (" - << i->branch_factor << ") ( timeouts " - << i->timeouts << " responses " << i->responses << ")\n"; - } + out << esc("31") << "error " << s.error; + out << esc("0") << std::endl; + continue; } - if (active_handle.is_valid()) + if (paused && !auto_managed) out << "paused"; + else if (paused && auto_managed) out << "queued"; + else out << state_str[s.state]; + + int seeds = 0; + int downloaders = 0; + + if (s.num_complete >= 0) seeds = s.num_complete; + else seeds = s.list_seeds; + + if (s.num_incomplete >= 0) downloaders = s.num_incomplete; + else downloaders = s.list_peers - s.list_seeds; + + out << "download: " << "(" << esc("32") << add_suffix(s.total_download) << term << ") " + "upload: " << esc("31") << (s.upload_rate > 0 ? add_suffix(s.upload_rate) + "/s ": " ") << term + << "(" << esc("31") << add_suffix(s.total_upload) << term << ") " + << "swarm: " << to_string(downloaders, 4) << ":" << to_string(seeds, 4) + << " bw queue: (" << s.up_bandwidth_queue << " | " << s.down_bandwidth_queue << ") " + "all-time (Rx: " << esc("32") << add_suffix(s.all_time_download) << term + << " Tx: " << esc("31") << add_suffix(s.all_time_upload) << term << ") " + << std::hex << s.seed_rank << std::dec << " " + << s.last_scrape << "\n" << esc("0"); + + if (torrent_index != active_torrent && s.state == torrent_status::seeding) continue; + char const* progress_bar_color = "33"; // yellow + if (s.state == torrent_status::checking_files + || s.state == torrent_status::downloading_metadata) { - torrent_handle h = active_handle; - torrent_status s = h.status(); - - if ((print_downloads && s.state != torrent_status::seeding) - || print_peers) - h.get_peer_info(peers); - - out << "====== " << h.name() << " ======" << std::endl; - - if (print_peers && !peers.empty()) - print_peer_info(out, peers); - - if (print_trackers) - { - std::vector tr = h.trackers(); - ptime now = time_now(); - for (std::vector::iterator i = tr.begin() - , end(tr.end()); i != end; ++i) - { - std::string url = i->url; - url.resize(55, ' '); - out << to_string(i->tier, 2) << " " << url << " " - << to_string(i->fails, 3) << " " << (i->verified?"OK ":"- "); - if (i->updating) out << "updating"; - else out << to_string(total_seconds(i->next_announce - now), 8); - out << "\n"; - } - } - - if (print_downloads) - { - h.get_download_queue(queue); - std::sort(queue.begin(), queue.end(), bind(&partial_piece_info::piece_index, _1) - < bind(&partial_piece_info::piece_index, _2)); - - std::vector pieces; - ses.get_cache_info(h.info_hash(), pieces); - - for (std::vector::iterator i = queue.begin(); - i != queue.end(); ++i) - { - cached_piece_info* cp = 0; - std::vector::iterator cpi = std::find_if(pieces.begin(), pieces.end() - , bind(&cached_piece_info::piece, _1) == i->piece_index); - if (cpi != pieces.end()) cp = &*cpi; - - out << to_string(i->piece_index, 4) << ": ["; - for (int j = 0; j < i->blocks_in_piece; ++j) - { - int index = peer_index(i->blocks[j].peer, peers); - char str[] = "+"; - if (index >= 0) - str[0] = (index < 10)?'0' + index:'A' + index - 10; - -#ifdef ANSI_TERMINAL_COLORS - if (cp && cp->blocks[j]) out << esc("36;7") << str << esc("0"); - else if (i->blocks[j].bytes_progress > 0 - && i->blocks[j].state == block_info::requested) - { - if (i->blocks[j].num_peers > 1) - out << esc("1;7"); - else - out << esc("33;7"); - out << to_string(i->blocks[j].bytes_progress / float(i->blocks[j].block_size) * 10, 1) << esc("0"); - } - else if (i->blocks[j].state == block_info::finished) out << esc("32;7") << str << esc("0"); - else if (i->blocks[j].state == block_info::writing) out << esc("35;7") << str << esc("0"); - else if (i->blocks[j].state == block_info::requested) out << str; - else out << " "; -#else - if (cp && cp->blocks[j]) out << "c"; - else if (i->blocks[j].state == block_info::finished) out << "#"; - else if (i->blocks[j].state == block_info::writing) out << "+"; - else if (i->blocks[j].state == block_info::requested) out << str; - else out << " "; -#endif - } - char const* piece_state[4] = {"", "slow", "medium", "fast"}; - out << "] " << piece_state[i->piece_state]; - if (cp) out << (i->piece_state > 0?" | ":"") << "cache age: " << (total_milliseconds(time_now() - cp->last_use) / 1000.f); - out << "\n"; - } - - for (std::vector::iterator i = pieces.begin() - , end(pieces.end()); i != end; ++i) - { - if (i->kind != cached_piece_info::read_cache) continue; - out << to_string(i->piece, 4) << ": ["; - for (std::vector::iterator k = i->blocks.begin() - , end(i->blocks.end()); k != end; ++k) - { -#ifdef ANSI_TERMINAL_COLORS - if (*k) out << esc("33;7") << " " << esc("0"); - else out << " "; -#else - if (*k) out << "#"; - else out << " "; -#endif - } - out << "] " << "cache age: " - << (total_milliseconds(time_now() - i->last_use) / 1000.f) - << "\n"; - } - out << "___________________________________\n"; - } - - if (print_file_progress - && s.state != torrent_status::seeding - && h.has_metadata()) - { - std::vector file_progress; - h.file_progress(file_progress); - torrent_info const& info = h.get_torrent_info(); - for (int i = 0; i < info.num_files(); ++i) - { - bool pad_file = info.file_at(i).pad_file; - if (!show_pad_files && pad_file) continue; - float progress = info.file_at(i).size > 0 - ?float(file_progress[i]) / info.file_at(i).size:1; - if (file_progress[i] == info.file_at(i).size) - out << progress_bar(1.f, 100, "32"); - else - out << progress_bar(progress, 100, "33"); - if (pad_file) out << esc("34"); - out << " " << to_string(progress * 100.f, 5) << "% " - << add_suffix(file_progress[i]) << " " - << info.file_at(i).path.leaf() << "\n"; - if (pad_file) out << esc("0"); - } - - out << "___________________________________\n"; - } - + progress_bar_color = "35"; // magenta } - - if (print_log) + else if (s.current_tracker.empty()) { - for (std::deque::iterator i = events.begin(); - i != events.end(); ++i) - { - out << "\n" << *i; - } + progress_bar_color = "31"; // red } - - clear_home(); - puts(out.str().c_str()); - - if (!monitor_dir.empty() - && next_dir_scan < time_now()) + else if (sess_stat.has_incoming_connections) { - scan_dir(monitor_dir, ses, handles, preferred_ratio - , compact_allocation_mode, save_path, torrent_upload_limit - , torrent_download_limit); - next_dir_scan = time_now() + seconds(poll_interval); + progress_bar_color = "32"; // green + } + if (sequential_download) + out << "sequential: "; + else + out << " progress: "; + + out << esc("32") << s.total_done << esc("0") << " Bytes "; + out.precision(4); + out.width(5); + out.fill(' '); + out << (s.progress*100) << "% "; + out << progress_bar(s.progress, terminal_width - 37, progress_bar_color) << "\n"; + if (print_piece_bar && s.progress < 1.f) + out << " " << piece_bar(s.pieces, terminal_width - 5) << "\n"; + out << " peers: " << esc("37") << s.num_peers << esc("0") << " (" << esc("37") << s.connect_candidates << esc("0") << ") " + << "seeds: " << esc("37") << s.num_seeds << esc("0") << " " + << "distributed copies: " << esc("37") << s.distributed_copies << esc("0") + << " sparse regions: " << s.sparse_regions + // << " magnet-link: " << make_magnet_uri(h) << "\n" + << " download: " << esc("32") << (s.download_rate > 0 ? add_suffix(s.download_rate) + "/s ": " ") << esc("0"); + boost::posix_time::time_duration t = s.next_announce; + out << " next announce: " << esc("37") + << to_string(t.hours(), 2) << ":" + << to_string(t.minutes(), 2) << ":" + << to_string(t.seconds(), 2) << esc("0") << " "; + out << "tracker: " << esc("36") << s.current_tracker << esc("0") << "\n"; + + if (torrent_index != active_torrent) continue; + active_handle = h; + } + + cache_status cs = ses.get_cache_status(); + if (cs.blocks_read < 1) cs.blocks_read = 1; + if (cs.blocks_written < 1) cs.blocks_written = 1; + + out << "==== conns: " << sess_stat.num_peers + << " down: " << esc("32") << add_suffix(sess_stat.download_rate) << "/s" << esc("0") + << " (" << esc("32") << add_suffix(sess_stat.total_download) << esc("0") << ")" + " up: " << esc("31") << add_suffix(sess_stat.upload_rate) << "/s" << esc("0") + << " (" << esc("31") << add_suffix(sess_stat.total_upload) << esc("0") << ")" + " tcp/ip: " + << esc("32") << add_suffix(sess_stat.ip_overhead_download_rate) << "/s" << esc("0") << " " + << esc("31") << add_suffix(sess_stat.ip_overhead_upload_rate) << "/s" << esc("0") + << " DHT: " + << esc("32") << add_suffix(sess_stat.dht_download_rate) << "/s" << esc("0") << " " + << esc("31") << add_suffix(sess_stat.dht_upload_rate) << "/s" << esc("0") + << " tracker: " + << esc("32") << add_suffix(sess_stat.tracker_download_rate) << "/s" << esc("0") << " " + << esc("31") << add_suffix(sess_stat.tracker_upload_rate) << "/s" << esc("0") << " ====\n" + "==== waste: " << add_suffix(sess_stat.total_redundant_bytes) + << " fail: " << add_suffix(sess_stat.total_failed_bytes) + << " unchoked: " << sess_stat.num_unchoked << " / " << sess_stat.allowed_upload_slots + << " bw queues: " << sess_stat.up_bandwidth_bytes_queue + << " (" << sess_stat.up_bandwidth_queue<< ")" + << " | " << sess_stat.down_bandwidth_bytes_queue + << " (" << sess_stat.down_bandwidth_queue<< ") " + " write cache hits: " << ((cs.blocks_written - cs.writes) * 100 / cs.blocks_written) << "% " + " read cache hits: " << (cs.blocks_read_hit * 100 / cs.blocks_read) << "% " + " cache size: " << add_suffix(cs.cache_size * 16 * 1024) + << " (" << add_suffix(cs.read_cache_size * 16 * 1024) << ")" + " ====\n" + "==== optimistic unchoke: " << sess_stat.optimistic_unchoke_counter + << " unchoke counter: " << sess_stat.unchoke_counter + << " ====" << std::endl; + + if (show_dht_status) + { + out << "DHT nodes: " << sess_stat.dht_nodes + << " DHT cached nodes: " << sess_stat.dht_node_cache + << " total DHT size: " << sess_stat.dht_global_nodes << std::endl; + for (std::vector::iterator i = sess_stat.active_requests.begin() + , end(sess_stat.active_requests.end()); i != end; ++i) + { + out << " " << i->type << " " << i->outstanding_requests << " (" + << i->branch_factor << ") ( timeouts " + << i->timeouts << " responses " << i->responses << ")\n"; } } - std::cout << "saving session state" << std::endl; - { - entry session_state = ses.state(); - boost::filesystem::ofstream out(".ses_state" - , std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), session_state); + if (active_handle.is_valid()) + { + torrent_handle h = active_handle; + torrent_status s = h.status(); + + if ((print_downloads && s.state != torrent_status::seeding) + || print_peers) + h.get_peer_info(peers); + + out << "====== " << h.name() << " ======" << std::endl; + + if (print_peers && !peers.empty()) + print_peer_info(out, peers); + + if (print_trackers) + { + std::vector tr = h.trackers(); + ptime now = time_now(); + for (std::vector::iterator i = tr.begin() + , end(tr.end()); i != end; ++i) + { + std::string url = i->url; + url.resize(55, ' '); + out << to_string(i->tier, 2) << " " << url << " " + << to_string(i->fails, 3) << " " << (i->verified?"OK ":"- "); + if (i->updating) out << "updating"; + else out << to_string(total_seconds(i->next_announce - now), 8); + out << "\n"; + } + } + + if (print_downloads) + { + h.get_download_queue(queue); + std::sort(queue.begin(), queue.end(), bind(&partial_piece_info::piece_index, _1) + < bind(&partial_piece_info::piece_index, _2)); + + std::vector pieces; + ses.get_cache_info(h.info_hash(), pieces); + + for (std::vector::iterator i = queue.begin(); + i != queue.end(); ++i) + { + cached_piece_info* cp = 0; + std::vector::iterator cpi = std::find_if(pieces.begin(), pieces.end() + , bind(&cached_piece_info::piece, _1) == i->piece_index); + if (cpi != pieces.end()) cp = &*cpi; + + out << to_string(i->piece_index, 4) << ": ["; + for (int j = 0; j < i->blocks_in_piece; ++j) + { + int index = peer_index(i->blocks[j].peer, peers); + char str[] = "+"; + if (index >= 0) + str[0] = (index < 10)?'0' + index:'A' + index - 10; + +#ifdef ANSI_TERMINAL_COLORS + if (cp && cp->blocks[j]) out << esc("36;7") << str << esc("0"); + else if (i->blocks[j].bytes_progress > 0 + && i->blocks[j].state == block_info::requested) + { + if (i->blocks[j].num_peers > 1) + out << esc("1;7"); + else + out << esc("33;7"); + out << to_string(i->blocks[j].bytes_progress / float(i->blocks[j].block_size) * 10, 1) << esc("0"); + } + else if (i->blocks[j].state == block_info::finished) out << esc("32;7") << str << esc("0"); + else if (i->blocks[j].state == block_info::writing) out << esc("35;7") << str << esc("0"); + else if (i->blocks[j].state == block_info::requested) out << str; + else out << " "; +#else + if (cp && cp->blocks[j]) out << "c"; + else if (i->blocks[j].state == block_info::finished) out << "#"; + else if (i->blocks[j].state == block_info::writing) out << "+"; + else if (i->blocks[j].state == block_info::requested) out << str; + else out << " "; +#endif + } + char const* piece_state[4] = {"", "slow", "medium", "fast"}; + out << "] " << piece_state[i->piece_state]; + if (cp) out << (i->piece_state > 0?" | ":"") << "cache age: " << (total_milliseconds(time_now() - cp->last_use) / 1000.f); + out << "\n"; + } + + for (std::vector::iterator i = pieces.begin() + , end(pieces.end()); i != end; ++i) + { + if (i->kind != cached_piece_info::read_cache) continue; + out << to_string(i->piece, 4) << ": ["; + for (std::vector::iterator k = i->blocks.begin() + , end(i->blocks.end()); k != end; ++k) + { +#ifdef ANSI_TERMINAL_COLORS + if (*k) out << esc("33;7") << " " << esc("0"); + else out << " "; +#else + if (*k) out << "#"; + else out << " "; +#endif + } + out << "] " << "cache age: " + << (total_milliseconds(time_now() - i->last_use) / 1000.f) + << "\n"; + } + out << "___________________________________\n"; + } + + if (print_file_progress + && s.state != torrent_status::seeding + && h.has_metadata()) + { + std::vector file_progress; + h.file_progress(file_progress); + torrent_info const& info = h.get_torrent_info(); + for (int i = 0; i < info.num_files(); ++i) + { + bool pad_file = info.file_at(i).pad_file; + if (!show_pad_files && pad_file) continue; + float progress = info.file_at(i).size > 0 + ?float(file_progress[i]) / info.file_at(i).size:1; + if (file_progress[i] == info.file_at(i).size) + out << progress_bar(1.f, 100, "32"); + else + out << progress_bar(progress, 100, "33"); + if (pad_file) out << esc("34"); + out << " " << to_string(progress * 100.f, 5) << "% " + << add_suffix(file_progress[i]) << " " + << info.file_at(i).path.leaf() << "\n"; + if (pad_file) out << esc("0"); + } + + out << "___________________________________\n"; + } + } -#ifndef TORRENT_DISABLE_DHT - std::cout << "saving DHT state" << std::endl; - dht_state = ses.dht_state(); - boost::filesystem::ofstream out(".dht_state" + if (print_log) + { + for (std::deque::iterator i = events.begin(); + i != events.end(); ++i) + { + out << "\n" << *i; + } + } + + clear_home(); + puts(out.str().c_str()); + + if (!monitor_dir.empty() + && next_dir_scan < time_now()) + { + scan_dir(monitor_dir, ses, handles, preferred_ratio + , allocation_mode == "compact", save_path, torrent_upload_limit + , torrent_download_limit); + next_dir_scan = time_now() + seconds(poll_interval); + } + } + + std::cout << "saving session state" << std::endl; + { + entry session_state = ses.state(); + boost::filesystem::ofstream out(".ses_state" , std::ios_base::binary); out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), dht_state); -#endif - std::cout << "closing session" << std::endl; - } -#ifndef BOOST_NO_EXCEPTIONS - catch (std::exception& e) - { - std::cout << e.what() << "\n"; + bencode(std::ostream_iterator(out), session_state); } + +#ifndef TORRENT_DISABLE_DHT + std::cout << "saving DHT state" << std::endl; + dht_state = ses.dht_state(); + boost::filesystem::ofstream out(".dht_state" + , std::ios_base::binary); + out.unsetf(std::ios_base::skipws); + bencode(std::ostream_iterator(out), dht_state); #endif + std::cout << "closing session" << std::endl; return 0; } diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index a7be383e4..cb0d7598e 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -57,81 +57,74 @@ int main(int argc, char* argv[]) boost::filesystem::path::default_name_check(boost::filesystem::no_check); #endif -#ifndef BOOST_NO_EXCEPTIONS - try + int size = file_size(argv[1]); + if (size > 10 * 1000000) { -#endif - - int size = file_size(argv[1]); - if (size > 10 * 1000000) - { - std::cerr << "file too big (" << size << "), aborting\n"; - return 1; - } - std::vector buf(size); - std::ifstream(argv[1], std::ios_base::binary).read(&buf[0], size); - lazy_entry e; - int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); - - if (ret != 0) - { - std::cerr << "invalid bencoding: " << ret << std::endl; - return 1; - } - - std::cout << "\n\n----- raw info -----\n\n"; - std::cout << e << std::endl; - - torrent_info t(e); - - // print info about torrent - std::cout << "\n\n----- torrent file info -----\n\n"; - std::cout << "nodes:\n"; - typedef std::vector > node_vec; - node_vec const& nodes = t.nodes(); - for (node_vec::const_iterator i = nodes.begin(), end(nodes.end()); - i != end; ++i) - { - std::cout << i->first << ":" << i->second << "\n"; - } - std::cout << "trackers:\n"; - for (std::vector::const_iterator i = t.trackers().begin(); - i != t.trackers().end(); ++i) - { - std::cout << i->tier << ": " << i->url << "\n"; - } - - std::cout << "number of pieces: " << t.num_pieces() << "\n"; - std::cout << "piece length: " << t.piece_length() << "\n"; - std::cout << "info hash: " << t.info_hash() << "\n"; - std::cout << "comment: " << t.comment() << "\n"; - std::cout << "created by: " << t.creator() << "\n"; - std::cout << "magnet link: " << make_magnet_uri(t) << "\n"; - std::cout << "name: " << t.name() << "\n"; - std::cout << "files:\n"; - int index = 0; - for (torrent_info::file_iterator i = t.begin_files(); - i != t.end_files(); ++i, ++index) - { - int first = t.map_file(index, 0, 1).piece; - int last = t.map_file(index, i->size - 1, 1).piece; - std::cout << " " << std::setw(11) << i->size - << " " - << (i->pad_file?'p':'-') - << (i->executable_attribute?'x':'-') - << (i->hidden_attribute?'h':'-') - << " " - << i->path.string() << "[ " << first << ", " - << last << " ]\n"; - } - -#ifndef BOOST_NO_EXCEPTIONS + std::cerr << "file too big (" << size << "), aborting\n"; + return 1; } - catch (std::exception& e) + std::vector buf(size); + std::ifstream(argv[1], std::ios_base::binary).read(&buf[0], size); + lazy_entry e; + int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); + + if (ret != 0) { - std::cout << e.what() << "\n"; + std::cerr << "invalid bencoding: " << ret << std::endl; + return 1; + } + + std::cout << "\n\n----- raw info -----\n\n"; + std::cout << e << std::endl; + + error_code ec; + torrent_info t(e, ec); + if (ec) + { + std::cout << ec.message() << std::endl; + return 1; + } + + // print info about torrent + std::cout << "\n\n----- torrent file info -----\n\n"; + std::cout << "nodes:\n"; + typedef std::vector > node_vec; + node_vec const& nodes = t.nodes(); + for (node_vec::const_iterator i = nodes.begin(), end(nodes.end()); + i != end; ++i) + { + std::cout << i->first << ":" << i->second << "\n"; + } + std::cout << "trackers:\n"; + for (std::vector::const_iterator i = t.trackers().begin(); + i != t.trackers().end(); ++i) + { + std::cout << i->tier << ": " << i->url << "\n"; + } + + std::cout << "number of pieces: " << t.num_pieces() << "\n"; + std::cout << "piece length: " << t.piece_length() << "\n"; + std::cout << "info hash: " << t.info_hash() << "\n"; + std::cout << "comment: " << t.comment() << "\n"; + std::cout << "created by: " << t.creator() << "\n"; + std::cout << "magnet link: " << make_magnet_uri(t) << "\n"; + std::cout << "name: " << t.name() << "\n"; + std::cout << "files:\n"; + int index = 0; + for (torrent_info::file_iterator i = t.begin_files(); + i != t.end_files(); ++i, ++index) + { + int first = t.map_file(index, 0, 1).piece; + int last = t.map_file(index, i->size - 1, 1).piece; + std::cout << " " << std::setw(11) << i->size + << " " + << (i->pad_file?'p':'-') + << (i->executable_attribute?'x':'-') + << (i->hidden_attribute?'h':'-') + << " " + << i->path.string() << "[ " << first << ", " + << last << " ]\n"; } -#endif return 0; } diff --git a/examples/simple_client.cpp b/examples/simple_client.cpp index f9a120c09..6b92c846b 100644 --- a/examples/simple_client.cpp +++ b/examples/simple_client.cpp @@ -54,28 +54,28 @@ int main(int argc, char* argv[]) return 1; } -#ifndef BOOST_NO_EXCEPTIONS - try -#endif + session s; + s.listen_on(std::make_pair(6881, 6889)); + add_torrent_params p; + p.save_path = "./"; + error_code ec; + p.ti = new torrent_info(argv[1], ec); + if (ec) { - session s; - s.listen_on(std::make_pair(6881, 6889)); - add_torrent_params p; - p.save_path = "./"; - p.ti = new torrent_info(argv[1]); - s.add_torrent(p); + std::cout << ec.message() << std::endl; + return 1; + } + s.add_torrent(p, ec); + if (ec) + { + std::cerr << ec.message() << std::endl; + return 1; + } - // wait for the user to end - char a; - std::cin.unsetf(std::ios_base::skipws); - std::cin >> a; - } -#ifndef BOOST_NO_EXCEPTIONS - catch (std::exception& e) - { - std::cout << e.what() << "\n"; - } -#endif + // wait for the user to end + char a; + std::cin.unsetf(std::ios_base::skipws); + std::cin >> a; return 0; } diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index 1acb88e23..536f51fba 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -73,6 +73,7 @@ namespace libtorrent duplicate_torrent, invalid_torrent_handle, invalid_entry_type, + missing_info_hash_in_uri, }; } diff --git a/include/libtorrent/magnet_uri.hpp b/include/libtorrent/magnet_uri.hpp index 88675dfe8..57eccafdb 100644 --- a/include/libtorrent/magnet_uri.hpp +++ b/include/libtorrent/magnet_uri.hpp @@ -48,6 +48,7 @@ namespace libtorrent std::string TORRENT_EXPORT make_magnet_uri(torrent_handle const& handle); std::string TORRENT_EXPORT make_magnet_uri(torrent_info const& info); +#ifndef BOOST_NO_EXCEPTIONS #ifndef TORRENT_NO_DEPRECATE // deprecated in 0.14 torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri @@ -60,6 +61,10 @@ namespace libtorrent torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri , add_torrent_params p); +#endif + + torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri + , add_torrent_params p, error_code& ec); } #endif diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index ad250ab5f..85900c6a6 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -172,7 +172,7 @@ namespace libtorrent torrent_info(fs::wpath const& filename); #endif - torrent_info(sha1_hash const& info_hash, error_code& ec); + torrent_info(sha1_hash const& info_hash); torrent_info(lazy_entry const& torrent_file, error_code& ec); torrent_info(char const* buffer, int size, error_code& ec); torrent_info(fs::path const& filename, error_code& ec); diff --git a/src/error_code.cpp b/src/error_code.cpp index 339965971..98a56d7e5 100644 --- a/src/error_code.cpp +++ b/src/error_code.cpp @@ -69,6 +69,7 @@ namespace libtorrent "torrent already exists in session", "invalid torrent handle used", "invalid type requested from entry", + "missing info-hash from URI", }; if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0])) return "Unknown error"; diff --git a/src/magnet_uri.cpp b/src/magnet_uri.cpp index 28a94daff..e83ee07cb 100644 --- a/src/magnet_uri.cpp +++ b/src/magnet_uri.cpp @@ -89,6 +89,7 @@ namespace libtorrent return ret.str(); } +#ifndef BOOST_NO_EXCEPTIONS #ifndef TORRENT_NO_DEPRECATE torrent_handle add_magnet_uri(session& ses, std::string const& uri , fs::path const& save_path @@ -121,27 +122,44 @@ namespace libtorrent torrent_handle add_magnet_uri(session& ses, std::string const& uri , add_torrent_params p) + { + error_code ec; + torrent_handle ret = add_magnet_uri(ses, uri, p, ec); + if (ec) throw libtorrent_exceptions(ec); + return ret; + } +#endif + torrent_handle add_magnet_uri(session& ses, std::string const& uri + , add_torrent_params p, error_code& ec) { std::string name; std::string tracker; - error_code ec; + error_code e; boost::optional display_name = url_has_argument(uri, "dn"); - if (display_name) name = unescape_string(display_name->c_str(), ec); + if (display_name) name = unescape_string(display_name->c_str(), e); boost::optional tracker_string = url_has_argument(uri, "tr"); - if (tracker_string) tracker = unescape_string(tracker_string->c_str(), ec); + if (tracker_string) tracker = unescape_string(tracker_string->c_str(), e); boost::optional btih = url_has_argument(uri, "xt"); - if (!btih) return torrent_handle(); + if (!btih) + { + ec = error_code(errors::missing_info_hash_in_uri, libtorrent_category); + return torrent_handle(); + } - if (btih->compare(0, 9, "urn:btih:") != 0) return torrent_handle(); + if (btih->compare(0, 9, "urn:btih:") != 0) + { + ec = error_code(errors::missing_info_hash_in_uri, libtorrent_category); + return torrent_handle(); + } sha1_hash info_hash(base32decode(btih->substr(9))); if (!tracker.empty()) p.tracker_url = tracker.c_str(); p.info_hash = info_hash; if (!name.empty()) p.name = name.c_str(); - return ses.add_torrent(p); + return ses.add_torrent(p, ec); } } diff --git a/src/session.cpp b/src/session.cpp index 77bf2c609..d090f6c35 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -313,6 +313,7 @@ namespace libtorrent return m_impl->add_torrent(params, ec); } +#ifndef BOOST_NO_EXCEPTIONS #ifndef TORRENT_NO_DEPRECATE // if the torrent already exists, this will throw duplicate_torrent torrent_handle session::add_torrent( @@ -381,6 +382,7 @@ namespace libtorrent p.userdata = userdata; return add_torrent(p); } +#endif #endif void session::remove_torrent(const torrent_handle& h, int options) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 0bc1717d2..b3f695ba3 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2420,7 +2420,6 @@ namespace aux { void session_impl::set_max_connections(int limit) { - TORRENT_ASSERT(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; @@ -2443,7 +2442,6 @@ namespace aux { void session_impl::set_max_half_open_connections(int limit) { - TORRENT_ASSERT(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; @@ -2454,7 +2452,6 @@ namespace aux { void session_impl::set_download_rate_limit(int bytes_per_second) { - TORRENT_ASSERT(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; @@ -2465,7 +2462,6 @@ namespace aux { void session_impl::set_upload_rate_limit(int bytes_per_second) { - TORRENT_ASSERT(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK;