From 341967dab77ed7accd4bcbabd73322e0a2fb19ac Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 8 Mar 2012 09:54:44 +0000 Subject: [PATCH] improve magnet link support. in RSS feeds for instance. Parsing of magnet links was factored out and moved to the proper place, in session_impl::add_torrent --- bindings/python/src/session.cpp | 29 +++++++++++--- docs/manual.rst | 34 ++++++++++++---- include/libtorrent/add_torrent_params.hpp | 9 ++++- include/libtorrent/magnet_uri.hpp | 16 ++++++-- src/magnet_uri.cpp | 49 ++++++++++++----------- src/rss.cpp | 1 - src/session.cpp | 16 -------- src/session_impl.cpp | 27 ++++++++++--- src/torrent.cpp | 13 +++++- test/test_primitives.cpp | 2 +- 10 files changed, 129 insertions(+), 67 deletions(-) diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 80ab0719e..2aa0476ab 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -4,6 +4,8 @@ #include #include +#include "Python.h" +#include #include #include #include // for bencode_map_entry @@ -154,12 +156,6 @@ namespace if (params.has_key("ti")) p.ti = extract >(params["ti"]); - std::string url; - if (params.has_key("tracker_url")) - { - string_storage.push_back(extract(params["tracker_url"])); - p.tracker_url = string_storage.back().c_str(); - } if (params.has_key("info_hash")) p.info_hash = extract(params["info_hash"]); if (params.has_key("name")) @@ -179,7 +175,28 @@ namespace if (params.has_key("storage_mode")) p.storage_mode = extract(params["storage_mode"]); + if (params.has_key("tracker_url")) + { + list l = extract(params["trackers"]); + int n = boost::python::len(l); + for(int i = 0; i < n; i++) + p.trackers.push_back(extract(l[i])); + } + + if (params.has_key("dht_nodes")) + { + list l = extract(params["dht_nodes"]); + int n = boost::python::len(l); + for(int i = 0; i < n; i++) + p.dht_nodes.push_back(extract >(l[i])); + } #ifndef TORRENT_NO_DEPRECATE + std::string url; + if (params.has_key("tracker_url")) + { + string_storage.push_back(extract(params["tracker_url"])); + p.tracker_url = string_storage.back().c_str(); + } if (params.has_key("seed_mode")) p.seed_mode = params["seed_mode"]; if (params.has_key("upload_mode")) diff --git a/docs/manual.rst b/docs/manual.rst index 63d54b566..0f2dbcc82 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -399,10 +399,14 @@ async_add_torrent() add_torrent() int version; boost::intrusive_ptr ti; + #ifndef TORRENT_NO_DEPRECATE char const* tracker_url; + #endif + std::vector trackers; + std::vector > dht_nodes; sha1_hash info_hash; - char const* name; - fs::path save_path; + std::string name; + std::string save_path; std::vector* resume_data; storage_mode_t storage_mode; storage_constructor_type storage; @@ -438,18 +442,22 @@ torrent file), the ``info_hash`` (the info hash of the torrent) or the ``url`` info-hash, the torrent file will be downloaded from peers, which requires them to support the metadata extension. For the metadata extension to work, libtorrent must be built with extensions enabled (``TORRENT_DISABLE_EXTENSIONS`` must not be -defined). It also takes an optional ``name`` argument. This may be 0 in case no -name should be assigned to the torrent. In case it's not 0, the name is used for +defined). It also takes an optional ``name`` argument. This may be left empty in case no +name should be assigned to the torrent. In case it's not, the name is used for the torrent as long as it doesn't have metadata. See ``torrent_handle::name``. If the torrent doesn't have a tracker, but relies on the DHT to find peers, the -``tracker_url`` can be 0, otherwise you might specify a tracker url that tracks this -torrent. +``trackers`` (or the deprecated ``tracker_url``) can specify tracker urls that +for the torrent. If you specify a ``url``, the torrent will be set in ``downloading_metadata`` state until the .torrent file has been downloaded. If there's any error while downloading, the torrent will be stopped and the torrent error state (``torrent_status::error``) -will indicate what went wrong. The ``url`` may also refer to a magnet link. +will indicate what went wrong. The ``url`` may refer to a magnet link or a regular +http URL. + +``dht_nodes`` is a list of hostname and port pairs, representing DHT nodes to be +added to the session (if DHT is enabled). The hostname may be an IP address. If the torrent you are trying to add already exists in the session (is either queued for checking, being checked or downloading) ``add_torrent()`` will throw @@ -6031,6 +6039,8 @@ it will throw libtorrent_exception_. add_magnet_uri() ---------------- +*deprecated* + :: torrent_handle add_magnet_uri(session& ses, std::string const& uri @@ -6052,6 +6062,16 @@ link through ``add_torrent_params::url`` argument to ``session::add_torrent()``. For more information about magnet links, see `magnet links`_. +parse_magnet_uri() +------------------ + + :: + + void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec); + +This function parses out information from the magnet link and populates the +``add_torrent_params`` object. + make_magnet_uri() ----------------- diff --git a/include/libtorrent/add_torrent_params.hpp b/include/libtorrent/add_torrent_params.hpp index 0b8395419..972b60b34 100644 --- a/include/libtorrent/add_torrent_params.hpp +++ b/include/libtorrent/add_torrent_params.hpp @@ -49,8 +49,9 @@ namespace libtorrent { add_torrent_params(storage_constructor_type sc = default_storage_constructor) : version(LIBTORRENT_VERSION_NUM) +#ifndef TORRENT_NO_DEPRECATE , tracker_url(0) - , name(0) +#endif , resume_data(0) , storage_mode(storage_mode_sparse) , storage(sc) @@ -114,9 +115,13 @@ namespace libtorrent // libtorrent version. Used for forward binary compatibility int version; boost::intrusive_ptr ti; +#ifndef TORRENT_NO_DEPRECATE char const* tracker_url; +#endif + std::vector trackers; + std::vector > dht_nodes; sha1_hash info_hash; - char const* name; + std::string name; std::string save_path; std::vector* resume_data; storage_mode_t storage_mode; diff --git a/include/libtorrent/magnet_uri.hpp b/include/libtorrent/magnet_uri.hpp index bedfdae0b..38b38b507 100644 --- a/include/libtorrent/magnet_uri.hpp +++ b/include/libtorrent/magnet_uri.hpp @@ -46,23 +46,31 @@ 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 +#ifndef BOOST_NO_EXCEPTIONS // deprecated in 0.14 + TORRENT_DEPRECATED_PREFIX torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri , std::string const& save_path , storage_mode_t storage_mode = storage_mode_sparse , bool paused = false , storage_constructor_type sc = default_storage_constructor , void* userdata = 0) TORRENT_DEPRECATED; + + // deprecated in 0.16. Instead, pass in the magnet link as add_torrent_params::url + TORRENT_DEPRECATED_PREFIX + torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri + , add_torrent_params p) TORRENT_DEPRECATED; #endif + // deprecated in 0.16. Instead, pass in the magnet link as add_torrent_params::url + TORRENT_DEPRECATED_PREFIX torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri - , add_torrent_params p); + , add_torrent_params p, error_code& ec) TORRENT_DEPRECATED; + #endif - torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri - , add_torrent_params p, error_code& ec); + TORRENT_EXPORT void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec); } #endif diff --git a/src/magnet_uri.cpp b/src/magnet_uri.cpp index 2fcd67eed..8719a05fb 100644 --- a/src/magnet_uri.cpp +++ b/src/magnet_uri.cpp @@ -137,8 +137,16 @@ namespace libtorrent return ret; } #endif + torrent_handle add_magnet_uri(session& ses, std::string const& uri , add_torrent_params p, error_code& ec) + { + parse_magnet_uri(uri, p, ec); + if (ec) return torrent_handle(); + return ses.add_torrent(p, ec); + } + + void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec) { std::string name; std::string tracker; @@ -146,21 +154,32 @@ namespace libtorrent error_code e; std::string display_name = url_has_argument(uri, "dn"); if (!display_name.empty()) name = unescape_string(display_name.c_str(), e); + + // parse trackers out of the magnet link std::string::size_type pos = std::string::npos; - std::string tracker_string = url_has_argument(uri, "tr", &pos); - if (!tracker_string.empty()) tracker = unescape_string(tracker_string.c_str(), e); + do + { + pos = uri.find("&tr=", pos); + if (pos == std::string::npos) break; + pos += 4; + error_code e; + std::string url = unescape_string(uri.substr(pos, uri.find('&', pos) - pos), e); + if (e) continue; + p.trackers.push_back(url); + } + while (pos != std::string::npos); std::string btih = url_has_argument(uri, "xt"); if (btih.empty()) { ec = errors::missing_info_hash_in_uri; - return torrent_handle(); + return; } if (btih.compare(0, 9, "urn:btih:") != 0) { ec = errors::missing_info_hash_in_uri; - return torrent_handle(); + return; } #ifndef TORRENT_DISABLE_DHT @@ -173,7 +192,7 @@ namespace libtorrent { int port = atoi(node.c_str()+divider+1); if (port != 0) - ses.add_dht_node(std::make_pair(node.substr(0, divider), port)); + p.dht_nodes.push_back(std::make_pair(node.substr(0, divider), port)); } node_pos = uri.find("&dht=", node_pos); @@ -187,26 +206,8 @@ namespace libtorrent if (btih.size() == 40 + 9) from_hex(&btih[9], 40, (char*)&info_hash[0]); else info_hash.assign(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(); - torrent_handle ret = ses.add_torrent(p, ec); - - int tier = 1; - // there might be more trackers in the url - while (pos != std::string::npos) - { - pos = uri.find("&tr=", pos); - if (pos == std::string::npos) break; - pos += 4; - error_code e; - std::string url = unescape_string(uri.substr(pos, uri.find('&', pos) - pos), e); - if (e) continue; - announce_entry ae(url); - ae.tier = tier++; - ret.add_tracker(ae); - } - return ret; + if (!name.empty()) p.name = name; } } diff --git a/src/rss.cpp b/src/rss.cpp index e06a8c2d6..f0a002f13 100644 --- a/src/rss.cpp +++ b/src/rss.cpp @@ -391,7 +391,6 @@ void feed::on_feed(error_code const& ec p.name = i->title.c_str(); error_code e; - // #error session_impl::add_torrent doesn't support magnet links via url torrent_handle h = m_ses.add_torrent(p, e); m_ses.m_alerts.post_alert(add_torrent_alert(h, p, e)); m_added.insert(make_pair(i->url, now)); diff --git a/src/session.cpp b/src/session.cpp index 29221b798..c4f07372b 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -591,13 +591,6 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS torrent_handle session::add_torrent(add_torrent_params const& params) { - if (string_begins_no_case("magnet:", params.url.c_str())) - { - add_torrent_params p(params); - p.url.clear(); - return add_magnet_uri(*this, params.url, p); - } - error_code ec; TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec)); if (ec) throw libtorrent_exception(ec); @@ -608,13 +601,6 @@ namespace libtorrent torrent_handle session::add_torrent(add_torrent_params const& params, error_code& ec) { ec.clear(); - if (string_begins_no_case("magnet:", params.url.c_str())) - { - add_torrent_params p(params); - p.url.clear(); - return add_magnet_uri(*this, params.url, p, ec); - } - TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec)); return r; } @@ -623,8 +609,6 @@ namespace libtorrent { add_torrent_params* p = new add_torrent_params(params); if (params.resume_data) p->resume_data = new std::vector(*params.resume_data); - if (params.tracker_url) p->tracker_url = strdup(params.tracker_url); - if (params.name) p->name = strdup(params.name); TORRENT_ASYNC_CALL1(async_add_torrent, p); } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 6aecadd0d..e275f0194 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -81,6 +81,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/build_config.hpp" #include "libtorrent/extensions.hpp" #include "libtorrent/random.hpp" +#include "libtorrent/magnet_uri.hpp" #if defined TORRENT_STATS && defined __MACH__ #include @@ -4724,26 +4725,42 @@ namespace aux { torrent_handle handle = add_torrent(*params, ec); m_alerts.post_alert(add_torrent_alert(handle, *params, ec)); delete params->resume_data; - free((char*)params->tracker_url); - free((char*)params->name); delete params; } - torrent_handle session_impl::add_torrent(add_torrent_params const& params + torrent_handle session_impl::add_torrent(add_torrent_params const& p , error_code& ec) { - TORRENT_ASSERT(!params.save_path.empty()); + TORRENT_ASSERT(!p.save_path.empty()); #ifndef TORRENT_NO_DEPRECATE - params.update_flags(); + p.update_flags(); #endif + add_torrent_params params = p; + if (string_begins_no_case("magnet:", params.url.c_str())) + { + parse_magnet_uri(params.url, params, ec); + if (ec) return torrent_handle(); + params.url.clear(); + } + if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0) { ec = errors::no_files_in_torrent; return torrent_handle(); } +#ifndef TORRENT_DISABLE_DHT + // add p.dht_nodes to the DHT, if enabled + if (m_dht && !p.dht_nodes.empty()) + { + for (std::vector >::const_iterator i = p.dht_nodes.begin() + , end(p.dht_nodes.end()); i != end; ++i) + m_dht->add_node(*i); + } +#endif + // INVARIANT_CHECK; if (is_aborted()) diff --git a/src/torrent.cpp b/src/torrent.cpp index f77d8de7c..ba176e8d8 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -520,7 +520,7 @@ namespace libtorrent } else { - if (p.name) m_name.reset(new std::string(p.name)); + if (!p.name.empty()) m_name.reset(new std::string(p.name)); } if (!m_url.empty() && m_uuid.empty()) m_uuid = m_url; @@ -554,6 +554,7 @@ namespace libtorrent if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url)); +#ifndef TORRENT_NO_DEPRECATE if (p.tracker_url && std::strlen(p.tracker_url) > 0) { m_trackers.push_back(announce_entry(p.tracker_url)); @@ -561,6 +562,16 @@ namespace libtorrent m_trackers.back().source = announce_entry::source_magnet_link; m_torrent_file->add_tracker(p.tracker_url); } +#endif + + for (std::vector::const_iterator i = p.trackers.begin() + , end(p.trackers.end()); i != end; ++i) + { + m_trackers.push_back(announce_entry(*i)); + m_trackers.back().fail_limit = 0; + m_trackers.back().source = announce_entry::source_magnet_link; + m_torrent_file->add_tracker(*i); + } if (settings().prefer_udp_trackers) prioritize_udp_trackers(); diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 9b6f2b012..e793f1cb1 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -1132,7 +1132,7 @@ int test_main() TEST_CHECK(f.open("test_file", file::read_write, ec)); #endif TEST_CHECK(!ec); - file::iovec_t b = {"test", 4}; + file::iovec_t b = {(void*)"test", 4}; TEST_CHECK(f.writev(0, &b, 1, ec) == 4); TEST_CHECK(!ec); char test_buf[5] = {0};