diff --git a/examples/Jamfile b/examples/Jamfile index a8862970b..92017cef2 100755 --- a/examples/Jamfile +++ b/examples/Jamfile @@ -27,5 +27,14 @@ exe dump_torrent : debug release ; -stage bin : dump_torrent simple_client client_test ; +exe make_torrent + : make_torrent.cpp + /torrent + : + multi + : debug release + ; + + +stage bin : dump_torrent simple_client client_test make_torrent ; diff --git a/examples/make_torrent.cpp b/examples/make_torrent.cpp new file mode 100755 index 000000000..527d39a9d --- /dev/null +++ b/examples/make_torrent.cpp @@ -0,0 +1,126 @@ +/* + +Copyright (c) 2003, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include + +#include "libtorrent/entry.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/file.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/hasher.hpp" + +#include +#include +#include + +using namespace boost::filesystem; +using namespace libtorrent; + +void add_files( + torrent_info& t + , path const& p + , path const& l) +{ + path f(p / l); + if (is_directory(f)) + { + for (directory_iterator i(f), end; i != end; ++i) + add_files(t, p, l / i->leaf()); + } + else + { + file f(f, file::in); + f.seek(0, file::end); + libtorrent::size_type size = f.tell(); + t.add_file(l, size); + } +} + + +int main(int argc, char* argv[]) +{ + using namespace libtorrent; + using namespace boost::filesystem; + + if (argc != 4) + { + std::cerr << "usage: make_torrent \n\n" + "the torrent file will be written to stdout.\n"; + return 1; + } + + path::default_name_check(native); + + try + { + torrent_info t; + path full_path = initial_path() / path(argv[3]); + ofstream out(initial_path() / path(argv[1]), std::ios_base::binary); + + int piece_size = 256 * 1024; + char const* creator_str = "libtorrent"; + + add_files(t, full_path.branch_path(), full_path.leaf()); + t.set_piece_size(piece_size); + + storage st(t, full_path.branch_path()); + t.add_tracker(argv[2]); + + // calculate the hash for all pieces + int num = t.num_pieces(); + std::vector buf(piece_size); + for (int i = 0; i < num; ++i) + { + st.read(&buf[0], i, 0, t.piece_size(i)); + hasher h(&buf[0], t.piece_size(i)); + t.set_hash(i, h.final()); + std::cerr << (i+1) << "/" << num << "\r"; + } + + t.set_creator(creator_str); + + // create the torrent and print it to stdout + entry e = t.create_torrent(); + libtorrent::bencode(std::ostream_iterator(out), e); + } + catch (std::exception& e) + { + std::cerr << e.what() << "\n"; + } + + return 0; +} + diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 4c2b6e726..a2929d1ff 100755 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -90,7 +90,6 @@ namespace libtorrent torrent_handle handle; }; - struct peer_error_alert: alert { peer_error_alert(address const& pip, peer_id const& pid, const std::string& msg) diff --git a/include/libtorrent/peer_id.hpp b/include/libtorrent/peer_id.hpp index 486ac00e5..163e56b70 100755 --- a/include/libtorrent/peer_id.hpp +++ b/include/libtorrent/peer_id.hpp @@ -131,6 +131,13 @@ namespace libtorrent { char c[2]; is >> c[0] >> c[1]; + if (c[0] < 0 || c[1] < 0 + || c[0] > 'f' || c[1] > 'f' + || is.fail()) + { + is.setstate(ios_base::failbit); + return is; + } *i = ((isdigit(c[0])?c[0]-'0':c[0]-'a'+10) << 4) + (isdigit(c[1])?c[1]-'0':c[1]-'a'+10); } diff --git a/include/libtorrent/socket.hpp b/include/libtorrent/socket.hpp index 056046a25..2f904fe9e 100755 --- a/include/libtorrent/socket.hpp +++ b/include/libtorrent/socket.hpp @@ -150,6 +150,7 @@ namespace libtorrent bool is_readable() const; bool is_writable() const; + bool has_error() const; enum error_code { @@ -178,6 +179,7 @@ namespace libtorrent is_connected, net_unreachable, not_initialized, + host_not_found, unknown_error }; diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 792a0f591..1dc355341 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -62,13 +62,13 @@ namespace libtorrent class session; std::vector get_filesizes( - const torrent_info& t - , const boost::filesystem::path& p); + torrent_info const& t + , boost::filesystem::path p); bool match_filesizes( - const torrent_info& t - , const boost::filesystem::path& p - , const std::vector& sizes); + torrent_info const& t + , boost::filesystem::path p + , std::vector const& sizes); struct file_allocation_failed: std::exception { @@ -93,7 +93,7 @@ namespace libtorrent // may throw file_error if storage for slot hasn't been allocated void write(const char* buf, int slot, int offset, int size); - bool move_storage(boost::filesystem::path const& save_path); + bool move_storage(boost::filesystem::path save_path); #ifndef NDEBUG // overwrites some slots with the diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 35b774cbc..d79d284e0 100755 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -86,16 +86,15 @@ namespace libtorrent { public: - torrent_info(const entry& torrent_file); - torrent_info( - int piece_size - , const char* name - , sha1_hash const& info_hash = sha1_hash(0)); + torrent_info(); + torrent_info(sha1_hash const& info_hash); + torrent_info(entry const& torrent_file); entry create_torrent() const; entry create_info_metadata() const; void set_comment(char const* str); void set_creator(char const* str); + void set_piece_size(int size); void set_hash(int index, const sha1_hash& h); void add_tracker(std::string const& url, int tier = 0); void add_file(boost::filesystem::path file, size_type size); diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 6f9e1b283..47a9b1ddb 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -250,6 +250,12 @@ namespace libtorrent m_request_time = boost::posix_time::second_clock::local_time(); } + if (m_socket->has_error()) + { + if (has_requester()) requester().tracker_request_error( + -1, "connection refused"); + return true; + } // if the socket isn't ready for reading, there's no point in continuing // trying to read from it diff --git a/src/stat.cpp b/src/stat.cpp index 55417e206..e1c28d419 100755 --- a/src/stat.cpp +++ b/src/stat.cpp @@ -79,7 +79,7 @@ void libtorrent::stat::second_tick() m_mean_download_rate += m_download_rate_history[i]; m_mean_upload_rate += m_upload_rate_history[i]; m_mean_download_payload_rate += m_download_payload_rate_history[i]; - m_mean_upload_payload_rate += m_download_payload_rate_history[i]; + m_mean_upload_payload_rate += m_upload_payload_rate_history[i]; } m_mean_download_rate /= history; diff --git a/src/storage.cpp b/src/storage.cpp index e2596b374..d4ca0245c 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -70,7 +70,7 @@ namespace std } #endif -namespace fs = boost::filesystem; +using namespace boost::filesystem; namespace { @@ -82,9 +82,9 @@ namespace log.flush(); } - fs::path get_filename( + path get_filename( libtorrent::torrent_info const& t - , fs::path const& p) + , path const& p) { assert(t.num_files() > 0); if (t.num_files() == 1) @@ -99,8 +99,9 @@ namespace libtorrent std::vector get_filesizes( const torrent_info& t - , const fs::path& p) + , path p) { + p = complete(p); std::vector sizes; for (torrent_info::file_iterator i = t.begin_files(); i != t.end_files(); @@ -123,11 +124,12 @@ namespace libtorrent } bool match_filesizes( - const torrent_info& t - , const fs::path& p - , const std::vector& sizes) + torrent_info const& t + , path p + , std::vector const& sizes) { if ((int)sizes.size() != t.num_files()) return false; + p = complete(p); std::vector::const_iterator s = sizes.begin(); for (torrent_info::file_iterator i = t.begin_files(); @@ -188,23 +190,24 @@ namespace libtorrent class storage::impl : public thread_safe_storage { public: - impl(const torrent_info& info, const fs::path& path) + impl(torrent_info const& info, path const& path) : thread_safe_storage(info.num_pieces()) , info(info) - , save_path(path) - {} + { + save_path = complete(path); + } - impl(const impl& x) + impl(impl const& x) : thread_safe_storage(x.info.num_pieces()) , info(x.info) , save_path(x.save_path) {} torrent_info const& info; - fs::path save_path; + path save_path; }; - storage::storage(const torrent_info& info, const fs::path& path) + storage::storage(const torrent_info& info, const path& path) : m_pimpl(new impl(info, path)) { assert(info.begin_files() != info.end_files()); @@ -216,21 +219,23 @@ namespace libtorrent } // returns true on success - bool storage::move_storage(fs::path const& save_path) + bool storage::move_storage(path save_path) { std::string old_path; std::string new_path; - if(!fs::exists(save_path)) - fs::create_directory(save_path); - else if(!fs::is_directory(save_path)) + save_path = complete(save_path); + + if(!exists(save_path)) + create_directory(save_path); + else if(!is_directory(save_path)) return false; if (m_pimpl->info.num_files() == 1) { - fs::path single_file = m_pimpl->info.begin_files()->path; + path single_file = m_pimpl->info.begin_files()->path; if (single_file.has_branch_path()) - fs::create_directory(save_path / single_file.branch_path()); + create_directory(save_path / single_file.branch_path()); old_path = (m_pimpl->save_path / single_file) .native_file_string(); @@ -366,7 +371,7 @@ namespace libtorrent if (left_to_read > 0) { ++file_iter; - fs::path path = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); + path path = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); file_offset = 0; in.open(path, file::in); @@ -406,8 +411,8 @@ namespace libtorrent ++file_iter; } - fs::path path(m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path)); - file out(path, file::out); + path p(m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path)); + file out(p, file::out); assert(file_offset < file_iter->size); @@ -462,12 +467,9 @@ namespace libtorrent ++file_iter; assert(file_iter != m_pimpl->info.end_files()); - - fs::path path = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); - + path p = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); file_offset = 0; - - out.open(path, file::out); + out.open(p, file::out); } } } @@ -485,7 +487,7 @@ namespace libtorrent impl( const torrent_info& info - , const fs::path& path); + , const path& path); void check_pieces( boost::mutex& mutex @@ -513,11 +515,13 @@ namespace libtorrent , int offset , int size); - fs::path const& save_path() const + path const& save_path() const { return m_save_path; } - bool move_storage(fs::path const& save_path) + bool move_storage(path save_path) { + m_save_path = complete(save_path); + if (m_storage.move_storage(save_path)) { m_save_path = save_path; @@ -576,7 +580,7 @@ namespace libtorrent // it can either be 'unassigned' or 'unallocated' std::vector m_slot_to_piece; - fs::path m_save_path; + path m_save_path; mutable boost::recursive_mutex m_mutex; @@ -587,17 +591,17 @@ namespace libtorrent piece_manager::impl::impl( const torrent_info& info - , const fs::path& save_path) + , const path& save_path) : m_storage(info, save_path) , m_info(info) - , m_save_path(save_path) , m_allocating(false) { + m_save_path = complete(save_path); } piece_manager::piece_manager( const torrent_info& info - , const fs::path& save_path) + , const path& save_path) : m_pimpl(new impl(info, save_path)) { } @@ -984,9 +988,9 @@ namespace libtorrent for (torrent_info::file_iterator file_iter = m_info.begin_files(), end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter) { - fs::path dir = m_save_path / get_filename(m_info, file_iter->path); - if (!fs::exists(dir.branch_path())) - fs::create_directories(dir.branch_path()); + path dir = m_save_path / get_filename(m_info, file_iter->path); + if (!exists(dir.branch_path())) + create_directories(dir.branch_path()); } std::vector piece_data(static_cast(m_info.piece_length())); @@ -1402,8 +1406,6 @@ namespace libtorrent INVARIANT_CHECK; - namespace fs = fs; - assert(!m_unallocated_slots.empty()); const int piece_size = static_cast(m_info.piece_length()); @@ -1441,12 +1443,12 @@ namespace libtorrent m_pimpl->allocate_slots(num_slots); } - fs::path const& piece_manager::save_path() const + path const& piece_manager::save_path() const { return m_pimpl->save_path(); } - bool piece_manager::move_storage(fs::path const& save_path) + bool piece_manager::move_storage(path const& save_path) { return m_pimpl->move_storage(save_path); } diff --git a/src/torrent.cpp b/src/torrent.cpp index a36daf804..c6bdfe4bb 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -188,7 +188,7 @@ namespace libtorrent , sha1_hash const& info_hash , boost::filesystem::path const& save_path , address const& net_interface) - : m_torrent_file(0, "", info_hash) + : m_torrent_file(info_hash) , m_abort(false) , m_paused(false) , m_just_paused(false) @@ -685,6 +685,7 @@ namespace libtorrent void torrent::try_next_tracker() { + using namespace boost::posix_time; ++m_currently_trying_tracker; if ((unsigned)m_currently_trying_tracker >= m_trackers.size()) @@ -697,7 +698,7 @@ namespace libtorrent ++m_failed_trackers; // if we've looped the tracker list, wait a bit before retrying m_currently_trying_tracker = 0; - m_next_request = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(delay); + m_next_request = second_clock::local_time() + seconds(delay); } else { @@ -727,8 +728,7 @@ namespace libtorrent boost::filesystem::path torrent::save_path() const { - assert(m_storage.get()); - return m_storage->save_path(); + return m_save_path; } bool torrent::move_storage(boost::filesystem::path const& save_path) diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index a1251c2e6..da6a6a605 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -57,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" using namespace libtorrent; +using namespace boost::filesystem; namespace { @@ -87,6 +89,15 @@ namespace + d.minutes() * 60 + d.seconds(); } + + void remove_dir(path& p) + { + assert(p.begin() != p.end()); + path tmp; + for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i) + tmp /= *i; + p = tmp; + } } namespace libtorrent @@ -112,18 +123,39 @@ namespace libtorrent // constructor used for creating new torrents // will not contain any hashes, comments, creation date // just the necessary to use it with piece manager - torrent_info::torrent_info( - int piece_size - , const char* name - , sha1_hash const& info_hash) - : m_piece_length(piece_size) + torrent_info::torrent_info(sha1_hash const& info_hash) + : m_piece_length(256 * 1024) , m_total_size(0) , m_info_hash(info_hash) - , m_name(name) + , m_name() , m_creation_date(second_clock::local_time()) { } + torrent_info::torrent_info() + : m_piece_length(256 * 1024) + , m_total_size(0) + , m_info_hash(0) + , m_name() + , m_creation_date(second_clock::local_time()) + { + } + + void torrent_info::set_piece_size(int size) + { + // make sure the size is an even 2 exponential +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (size & (1 << i)) + { + assert((size & ~(1 << i)) == 0); + break; + } + } +#endif + m_piece_length = size; + } void torrent_info::parse_info_section(entry const& info) { @@ -274,6 +306,26 @@ namespace libtorrent void torrent_info::add_file(boost::filesystem::path file, size_type size) { + assert(file.begin() != file.end()); + + if (m_files.empty()) + { + m_name = file.string(); + } + else + { +#ifndef NDEBUG + if (m_files.size() == 1) + assert(*m_files.front().path.begin() == *file.begin()); + else + assert(m_name == *file.begin()); +#endif + m_name = *file.begin(); + if (m_files.size() == 1) + remove_dir(m_files.front().path); + remove_dir(file); + } + file_entry e; e.path = file; e.size = size; @@ -313,13 +365,15 @@ namespace libtorrent info["length"] = m_total_size; + assert(!m_files.empty()); + if (m_files.size() == 1) { info["name"] = m_files.front().path.string(); } else { - info["name"] = m_name; + info["name"] = m_files.front().path.root_name(); } if (m_files.size() > 1)