diff --git a/examples/Jamfile b/examples/Jamfile index 4abba7feb..3314bb802 100644 --- a/examples/Jamfile +++ b/examples/Jamfile @@ -9,8 +9,6 @@ if $(BOOST_ROOT) use-project /boost : $(BOOST_ROOT) ; } -lib regex : : boost_regex ; - project client_test : requirements multi /torrent//torrent @@ -18,9 +16,7 @@ project client_test static ; -exe client_test : client_test.cpp - : /boost/regex - ; +exe client_test : client_test.cpp ; exe simple_client : simple_client.cpp ; exe dump_torrent : dump_torrent.cpp ; diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 9888b2009..e1694ec42 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -30,10 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. */ -#include -#include #include -#include #include "libtorrent/config.hpp" @@ -43,9 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include -#include #ifdef _MSC_VER #pragma warning(pop) @@ -147,7 +142,7 @@ bool sleep_and_input(char* c) void clear_home() { - std::cout << "\033[2J\033[0;0H"; + puts("\033[2J\033[0;0H"); } #endif @@ -169,7 +164,8 @@ bool print_block = false; bool print_peer_rate = false; bool print_fails = false; bool print_send_bufs = true; -std::ofstream g_log_file; + +FILE* g_log_file = 0; int active_torrent = 0; @@ -218,13 +214,21 @@ std::string& to_string(float v, int width, int precision = 3) ++round_robin; if (round_robin >= num_strings) round_robin = 0; ret.resize(20); - int size = std::sprintf(&ret[0], "%*.*f", width, precision, v); + int size = std::snprintf(&ret[0], 20, "%*.*f", width, precision, v); ret.resize((std::min)(size, width)); return ret; } -std::string const& add_suffix(float val) +std::string add_suffix(float val, char const* suffix = 0) { + std::string ret; + if (val == 0) + { + ret.resize(4 + 2, ' '); + if (suffix) ret.resize(4 + 2 + strlen(suffix), ' '); + return ret; + } + const char* prefix[] = {"kB", "MB", "GB", "TB"}; const int num_prefix = sizeof(prefix) / sizeof(const char*); for (int i = 0; i < num_prefix; ++i) @@ -232,13 +236,15 @@ std::string const& add_suffix(float val) val /= 1000.f; if (std::fabs(val) < 1000.f) { - std::string& ret = to_string(val, 4); + ret = to_string(val, 4); ret += prefix[i]; + if (suffix) ret += suffix; return ret; } } - std::string& ret = to_string(val, 4); + ret = to_string(val, 4); ret += "PB"; + if (suffix) ret += suffix; return ret; } @@ -319,24 +325,24 @@ int peer_index(libtorrent::tcp::endpoint addr, std::vector const& peers) +void print_peer_info(std::string& out, std::vector const& peers) { using namespace libtorrent; - if (print_ip) out << "IP "; + if (print_ip) out += "IP "; #ifndef TORRENT_DISABLE_GEO_IP - if (print_as) out << "AS "; + if (print_as) out += "AS "; #endif - out << "down (total | peak ) up (total | peak ) sent-req recv flags source "; - if (print_fails) out << "fail hshf "; - if (print_send_bufs) out << "rq sndb quota rcvb q-bytes "; - if (print_timers) out << "inactive wait timeout q-time "; - out << "disk rtt "; - if (print_block) out << "block-progress "; + out += "down (total | peak ) up (total | peak ) sent-req recv flags source "; + if (print_fails) out += "fail hshf "; + if (print_send_bufs) out += "rq sndb quota rcvb q-bytes "; + if (print_timers) out += "inactive wait timeout q-time "; + out += "disk rtt "; + if (print_block) out += "block-progress "; #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES - out << "country "; + out += "country "; #endif - if (print_peer_rate) out << "peer-rate "; - out << "client \n"; + if (print_peer_rate) out += "peer-rate "; + out += "client \n"; for (std::vector::const_iterator i = peers.begin(); i != peers.end(); ++i) @@ -344,126 +350,149 @@ void print_peer_info(std::ostream& out, std::vector const if (i->flags & (peer_info::handshake | peer_info::connecting | peer_info::queued)) continue; - out.fill(' '); if (print_ip) { + char str[100]; error_code ec; - std::stringstream ip; - ip << i->ip.address().to_string(ec) << ":" << i->ip.port(); - out.width(22); - out << ip.str() << " "; + snprintf(str, sizeof(str), "%-22s:%5d ", i->ip.address().to_string(ec).c_str(), i->ip.port()); + out += str; } #ifndef TORRENT_DISABLE_GEO_IP if (print_as) { - std::string as_name = i->inet_as_name; - if (as_name.size() > 42) as_name.resize(42); - out.width(42); - out << as_name << " "; + char str[100]; + error_code ec; + snprintf(str, sizeof(str), "%42s ", i->inet_as_name.c_str()); + out += str; } #endif - out.width(2); - out << esc("32") << (i->down_speed > 0 ? add_suffix(i->down_speed) + "/s " : " ") - << "(" << (i->total_download > 0 ? add_suffix(i->total_download) : " ") << "|" - << (i->download_rate_peak > 0 ? add_suffix(i->download_rate_peak) + "/s" : " ") << ") " << esc("0") - << esc("31") << (i->up_speed > 0 ? add_suffix(i->up_speed) + "/s ": " ") - << "(" << (i->total_upload > 0 ? add_suffix(i->total_upload) : " ") << "|" - << (i->upload_rate_peak > 0 ? add_suffix(i->upload_rate_peak) + "/s" : " ") << ") " << esc("0") - << to_string(i->download_queue_length, 3) << " (" - << to_string(i->target_dl_queue_length, 3) << ") " - << to_string(i->upload_queue_length, 3) << " " - << ((i->flags & peer_info::interesting)?'I':'.') - << ((i->flags & peer_info::choked)?'C':'.') - << ((i->flags & peer_info::remote_interested)?'i':'.') - << ((i->flags & peer_info::remote_choked)?'c':'.') - << ((i->flags & peer_info::supports_extensions)?'e':'.') - << ((i->flags & peer_info::local_connection)?'l':'r') - << ((i->flags & peer_info::seed)?'s':'.') - << ((i->flags & peer_info::on_parole)?'p':'.') - << ((i->flags & peer_info::optimistic_unchoke)?'O':'.') - << ((i->read_state == peer_info::bw_limit)?'r': - (i->read_state == peer_info::bw_network)?'R':'.') - << ((i->write_state == peer_info::bw_limit)?'w': - (i->write_state == peer_info::bw_network)?'W':'.') - << ((i->flags & peer_info::snubbed)?'S':'.') - << ((i->flags & peer_info::upload_only)?'U':'D') + char str[500]; + snprintf(str, sizeof(str), "%s%s (%s|%s) %s%s (%s|%s) %s" + , esc("32"), add_suffix(i->down_speed, "/s").c_str() + , add_suffix(i->total_download).c_str(), add_suffix(i->download_rate_peak, "/s").c_str() + , esc("31"), add_suffix(i->up_speed, "/s").c_str(), add_suffix(i->total_upload).c_str() + , add_suffix(i->upload_rate_peak, "/s").c_str(), esc("0")); + out += str; + + snprintf(str, sizeof(str), "%3d (%3d) %3d " + , i->download_queue_length, i->target_dl_queue_length, i->upload_queue_length); + out += str; + + snprintf(str, sizeof(str), "%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c%c%c%c%c " + , (i->flags & peer_info::interesting)?'I':'.' + , (i->flags & peer_info::choked)?'C':'.' + , (i->flags & peer_info::remote_interested)?'i':'.' + , (i->flags & peer_info::remote_choked)?'c':'.' + , (i->flags & peer_info::supports_extensions)?'e':'.' + , (i->flags & peer_info::local_connection)?'l':'r' + , (i->flags & peer_info::seed)?'s':'.' + , (i->flags & peer_info::on_parole)?'p':'.' + , (i->flags & peer_info::optimistic_unchoke)?'O':'.' + , (i->read_state == peer_info::bw_limit)?'r': + (i->read_state == peer_info::bw_network)?'R':'.' + , (i->write_state == peer_info::bw_limit)?'w': + (i->write_state == peer_info::bw_network)?'W':'.' + , (i->flags & peer_info::snubbed)?'S':'.' + , (i->flags & peer_info::upload_only)?'U':'D' #ifndef TORRENT_DISABLE_ENCRYPTION - << ((i->flags & peer_info::rc4_encrypted)?'E': - (i->flags & peer_info::plaintext_encrypted)?'e':'.') + , (i->flags & peer_info::rc4_encrypted)?'E': + (i->flags & peer_info::plaintext_encrypted)?'e':'.' #else - << ".." + , '.' #endif - << " " - << ((i->source & peer_info::tracker)?"T":"_") - << ((i->source & peer_info::pex)?"P":"_") - << ((i->source & peer_info::dht)?"D":"_") - << ((i->source & peer_info::lsd)?"L":"_") - << ((i->source & peer_info::resume_data)?"R":"_") << " "; + , (i->source & peer_info::tracker)?'T':'_' + , (i->source & peer_info::pex)?'P':'_' + , (i->source & peer_info::dht)?'D':'_' + , (i->source & peer_info::lsd)?'L':'_' + , (i->source & peer_info::resume_data)?'R':'_'); + out += str; + if (print_fails) { - out << to_string(i->failcount, 3) << " " - << to_string(i->num_hashfails, 3) << " "; + snprintf(str, sizeof(str), "%3d %3d " + , i->failcount, i->num_hashfails); + out += str; } if (print_send_bufs) { - out << to_string(i->requests_in_buffer, 2) << " " - << to_string(i->used_send_buffer, 6) << " ("<< add_suffix(i->send_buffer_size) << ") " - << to_string(i->send_quota, 5) << " " - << to_string(i->used_receive_buffer, 6) << " ("<< add_suffix(i->receive_buffer_size) << ") " - << to_string(i->queue_bytes, 6) << " "; + snprintf(str, sizeof(str), "%2d %6d (%s) %5d %6d (%s) %6d " + , i->requests_in_buffer, i->used_send_buffer, add_suffix(i->send_buffer_size).c_str() + , i->send_quota, i->used_receive_buffer, add_suffix(i->receive_buffer_size).c_str() + , i->queue_bytes); + out += str; } if (print_timers) { - out << to_string(total_seconds(i->last_active), 8) << " " - << to_string(total_seconds(i->last_request), 4) << " " - << to_string(i->request_timeout, 7) << " " - << to_string(total_seconds(i->download_queue_time), 6) << " "; + snprintf(str, sizeof(str), "%8d %4d %7d %6d " + , total_seconds(i->last_active) + , total_seconds(i->last_request) + , i->request_timeout + , total_seconds(i->download_queue_time)); + out += str; } - out << add_suffix(i->pending_disk_bytes) << " " - << to_string(i->rtt, 4) << " "; + snprintf(str, sizeof(str), "%s %4d " + , add_suffix(i->pending_disk_bytes).c_str() + , i->rtt); + out += str; if (print_block) { if (i->downloading_piece_index >= 0) { - out << progress_bar( + out += progress_bar( i->downloading_progress / float(i->downloading_total), 14); } else { - out << progress_bar(0.f, 14); + out += progress_bar(0.f, 14); } } #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES if (i->country[0] == 0) { - out << " .."; + out += " .."; } else { - out << " " << i->country[0] << i->country[1]; + snprintf(str, sizeof(str), " %c%c", i->country[0], i->country[1]); + out += str; } #endif - if (print_peer_rate) out << " " << (i->remote_dl_rate > 0 ? add_suffix(i->remote_dl_rate) + "/s ": " "); - out << " "; + if (print_peer_rate) + { + snprintf(str, sizeof(str), " %s", add_suffix(i->remote_dl_rate, "/s").c_str()); + out += str; + } + out += " "; if (i->flags & peer_info::handshake) { - out << esc("31") << " waiting for handshake" << esc("0") << "\n"; + out += esc("31"); + out += " waiting for handshake"; + out += esc("0"); + out += "\n"; } else if (i->flags & peer_info::connecting) { - out << esc("31") << " connecting to peer" << esc("0") << "\n"; + out += esc("31"); + out += " connecting to peer"; + out += esc("0"); + out += "\n"; } else if (i->flags & peer_info::queued) { - out << esc("33") << " queued" << esc("0") << "\n"; + out += esc("33"); + out += " queued"; + out += esc("0"); + out += "\n"; } else { - out << " " << i->client << "\n"; + out += " "; + out += i->client; + out += "\n"; } } } @@ -498,16 +527,16 @@ void add_torrent(libtorrent::session& ses t = new torrent_info(torrent.c_str(), ec); if (ec) { - std::cout << torrent << ": " << ec.message() << std::endl; + fprintf(stderr, "%s: %s\n", torrent.c_str(), ec.message().c_str()); return; } - std::cout << t->name() << std::endl; + printf("%s\n", t->name().c_str()); add_torrent_params p; lazy_entry resume_data; - std::string filename = (save_path / (t->name() + ".fastresume")).string(); + std::string filename = (save_path / (t->name() + ".resume")).string(); std::vector buf; if (load_file(filename.c_str(), buf) == 0) @@ -602,27 +631,45 @@ libtorrent::torrent_handle get_active_torrent(handles_t const& handles) return i->second; } -void print_alert(libtorrent::alert const* a, std::ostream& os) +void print_alert(libtorrent::alert const* a, std::string& str) { using namespace libtorrent; #ifdef ANSI_TERMINAL_COLORS if (a->category() & alert::error_notification) { - os << esc("31"); + str += esc("31"); } else if (a->category() & (alert::peer_notification | alert::storage_notification)) { - os << esc("33"); + str += esc("33"); } #endif - os << "[" << time_now_string() << "] " << a->message(); + str += "["; + str += time_now_string(); + str += "] "; + str += a->message(); #ifdef ANSI_TERMINAL_COLORS - os << esc("0"); + str += esc("0"); #endif - if (g_log_file.good()) - g_log_file << "[" << time_now_string() << "] " << a->message() << std::endl; + if (g_log_file) + fprintf(g_log_file, "[%s] %s\n", time_now_string(), a->message().c_str()); +} + +int save_file(boost::filesystem::path const& filename, std::vector& v) +{ + using namespace libtorrent; + + file f; + error_code ec; + if (!f.open(filename, file::write_only, ec)) return -1; + if (ec) return -1; + file::iovec_t b = {&v[0], v.size()}; + size_type written = f.writev(0, &b, 1, ec); + if (written != v.size()) return -3; + if (ec) return -3; + return 0; } void handle_alert(libtorrent::session& ses, libtorrent::alert* a @@ -646,10 +693,9 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a TORRENT_ASSERT(p->resume_data); if (p->resume_data) { - boost::filesystem::ofstream out(h.save_path() / (h.name() + ".fastresume") - , std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), *p->resume_data); + std::vector out; + bencode(std::back_inserter(out), *p->resume_data); + save_file(h.save_path() / (h.name() + ".resume"), out); if (std::find_if(handles.begin(), handles.end() , bind(&handles_t::value_type::second, _1) == h) == handles.end()) ses.remove_torrent(h); @@ -677,7 +723,7 @@ int main(int argc, char* argv[]) if (argc == 1) { - std::cerr << "usage: client_test [OPTIONS] [TORRENT|MAGNETURL]\n\n" + fprintf(stderr, "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" @@ -702,7 +748,7 @@ int main(int argc, char* argv[]) " -C sets the max cache size. Specified in 16kB blocks\n" "\n\n" "TORRENT is a path to a .torrent file\n" - "MAGNETURL is a magnet: url\n" + "MAGNETURL is a magnet: url\n") ; return 0; } @@ -728,12 +774,11 @@ int main(int argc, char* argv[]) session ses(fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) , session::start_default_features | session::add_default_plugins, alert::all_categories); - 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())); + std::vector in; + if (load_file(".ses_state", in) == 0) + { + ses.load_state(bdecode(in.begin(), in.end())); + } #ifndef TORRENT_DISABLE_DHT settings.use_dht_as_fallback = false; @@ -745,14 +790,10 @@ int main(int argc, char* argv[]) 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); + if (load_file(".dht_state", in) == 0) + { + ses.start_dht(bdecode(in.begin(), in.end())); + } #endif #ifndef TORRENT_DISABLE_GEO_IP @@ -771,7 +812,6 @@ int main(int argc, char* argv[]) 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) { @@ -786,12 +826,12 @@ int main(int argc, char* argv[]) 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; + printf("adding MANGET link: %s\n", argv[i]); error_code ec; torrent_handle h = add_magnet_uri(ses, argv[i], p, ec); if (ec) { - std::cerr << ec.message() << std::endl; + fprintf(stderr, "%s\n", ec.message().c_str()); continue; } @@ -806,13 +846,15 @@ int main(int argc, char* argv[]) } // match it against the @ format - boost::cmatch what; - if (boost::regex_match(argv[i], what, ex)) + if (strlen(argv[i]) > 45 + && is_hex(argv[i], 40) + && string_begins_no_case(argv[i] + 40, "@http")) { - sha1_hash info_hash = boost::lexical_cast(what[1]); + sha1_hash info_hash; + from_hex(argv[i], 40, (char*)&info_hash[0]); add_torrent_params p; - p.name = std::string(what[2]).c_str(); + p.tracker_url = argv[i] + 41; p.info_hash = info_hash; p.save_path = save_path; p.storage_mode = allocation_mode == "compact" ? storage_mode_compact @@ -824,7 +866,7 @@ int main(int argc, char* argv[]) torrent_handle h = ses.add_torrent(p, ec); if (ec) { - std::cerr << ec.message() << std::endl; + fprintf(stderr, "%s\n", ec.message().c_str()); continue; } @@ -850,7 +892,7 @@ int main(int argc, char* argv[]) char const* arg = argv[i+1]; switch (argv[i][1]) { - case 'f': g_log_file.open(arg); break; + case 'f': g_log_file = fopen(arg, "w+"); break; case 'o': ses.set_max_half_open_connections(atoi(arg)); break; case 'p': listen_port = atoi(arg); break; case 'r': @@ -870,6 +912,7 @@ int main(int argc, char* argv[]) case 't': poll_interval = atoi(arg); break; case 'x': { + /* std::ifstream in(arg); ip_filter filter; while (in.good()) @@ -894,6 +937,7 @@ int main(int argc, char* argv[]) filter.add_rule(start, last, flags); } ses.set_ip_filter(filter); + */ } break; case 'c': ses.set_max_connections(atoi(arg)); break; @@ -952,22 +996,25 @@ int main(int argc, char* argv[]) if (c == 'm') { - std::cout << "saving peers for torrents" << std::endl; + printf("saving peers for torrents\n"); 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()); + FILE* f = fopen(("peers_" + i->second.name()).c_str(), "w+"); + if (!f) break; for (std::vector::iterator k = peers.begin() , end(peers.end()); k != end; ++k) { - f << k->ip.address() + fprintf(f, "%s\t%d\n", print_address(k->ip.address()).c_str() #ifndef TORRENT_DISABLE_GEO_IP - << "\t" << ses.as_for_ip(k->ip.address()) + , ses.as_for_ip(k->ip.address()) +#else + , 0 #endif - << std::endl; + ); } } } @@ -986,27 +1033,28 @@ int main(int argc, char* argv[]) if (h.is_paused()) continue; if (!h.has_metadata()) continue; - std::cout << "saving resume data for " << h.name() << std::endl; + printf("saving resume data for %s\n", h.name().c_str()); // 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; + printf("waiting for resume data\n"); 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; + printf(" aborting with %d outstanding " + "torrents to save resume data for", num_resume_data); break; } std::auto_ptr holder = ses.pop_alert(); - ::print_alert(holder.get(), std::cout); - std::cout << std::endl; + std::string log; + ::print_alert(holder.get(), log); + printf("%s\n", log.c_str()); if (dynamic_cast(a)) { @@ -1021,10 +1069,9 @@ int main(int argc, char* argv[]) 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); + std::vector out; + bencode(std::back_inserter(out), *rd->resume_data); + save_file(h.save_path() / (h.name() + ".resume"), out); } break; } @@ -1115,12 +1162,12 @@ int main(int argc, char* argv[]) std::string now = time_now_string(); while (a.get()) { - std::stringstream event_string; + std::string event_string; ::print_alert(a.get(), event_string); ::handle_alert(ses, a.get(), handles); - events.push_back(event_string.str()); + events.push_back(event_string); if (events.size() >= 20) events.pop_front(); a = ses.pop_alert(); @@ -1128,13 +1175,14 @@ int main(int argc, char* argv[]) session_status sess_stat = ses.status(); - std::stringstream out; - out << "[q] quit [i] toggle peers [d] toggle downloading pieces [p] toggle paused " + std::string 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"; + char str[500]; int torrent_index = 0; torrent_handle active_handle; for (handles_t::iterator i = handles.begin(); @@ -1159,44 +1207,44 @@ int main(int argc, char* argv[]) if (active_torrent == torrent_index) { term = "\x1b[0m\x1b[7m"; - out << esc("7") << "*"; + out += esc("7"); + out += "*"; } else { - out << " "; + out += " "; } int queue_pos = h.queue_position(); - if (queue_pos == -1) out << "- "; - else out << std::setw(3) << queue_pos; + if (queue_pos == -1) out += "- "; + else + { + snprintf(str, sizeof(str), "%-3d", queue_pos); + out += str; + } - if (h.is_paused()) out << esc("34"); - else out << esc("37"); - out << std::setw(40) << std::setiosflags(std::ios::left); + if (h.is_paused()) out += esc("34"); + else out += esc("37"); - std::string name = h.name(); - if (name.size() > 40) name.resize(40); - out << name; - - out << term << " "; + snprintf(str, sizeof(str), "%-40s %s ", h.name().c_str(), term); + out += str; 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; + out += esc("31"); + out += "error "; + out += s.error; + out += esc("0"); + out += "\n"; 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; @@ -1206,15 +1254,18 @@ int main(int argc, char* argv[]) 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"); + snprintf(str, sizeof(str), "%-13s download: (%s%s%s) upload: %s%s%s (%s%s%s) swarm: %4d:%4d" + " bw queue: (%d|%d) all-time (Rx: %s%s%s Tx: %s%s%s) seed rank: %x%s\n" + , (paused && !auto_managed)?"paused":(paused && auto_managed)?"queued":state_str[s.state] + , esc("32"), add_suffix(s.total_download).c_str(), term + , esc("31"), add_suffix(s.upload_rate, "/s").c_str(), term + , esc("31"), add_suffix(s.total_upload).c_str(), term + , downloaders, seeds + , s.up_bandwidth_queue, s.down_bandwidth_queue + , esc("32"), add_suffix(s.all_time_download).c_str(), term + , esc("31"), add_suffix(s.all_time_upload).c_str(), term + , s.seed_rank, esc("0")); + out += str; if (torrent_index != active_torrent && s.state == torrent_status::seeding) continue; char const* progress_bar_color = "33"; // yellow @@ -1231,31 +1282,35 @@ int main(int argc, char* argv[]) { 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"; + snprintf(str, sizeof(str), " %-10s: %s%-10lld%s Bytes %6.2f%% %s\n" + , sequential_download?"sequential":"progress" + , esc("32"), s.total_done, esc("0") + , s.progress*100.f + , progress_bar(s.progress, terminal_width - 42, progress_bar_color).c_str()); + out += str; + 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"); + { + out += " "; + out += piece_bar(s.pieces, terminal_width - 7); + out += "\n"; + } + 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"; + snprintf(str, sizeof(str) + , " peers: %s%d%s (%s%d%s) seeds: %s%d%s distributed copies: %s%4.2f%s " + "sparse regions: %d download: %s%s%s next announce: %s%02d:%02d:%02d%s " + "tracker: %s%s%s\n" + , esc("37"), s.num_peers, esc("0") + , esc("37"), s.connect_candidates, esc("0") + , esc("37"), s.num_seeds, esc("0") + , esc("37"), s.distributed_copies, esc("0") + , s.sparse_regions + , esc("32"), add_suffix(s.download_rate, "/s").c_str(), esc("0") + , esc("37"), t.hours(), t.minutes(), t.seconds(), esc("0") + , esc("36"), s.current_tracker.c_str(), esc("0")); + out += str; if (torrent_index != active_torrent) continue; active_handle = h; @@ -1265,48 +1320,53 @@ int main(int argc, char* argv[]) 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) << ") / " - << add_suffix(cs.total_used_buffers * 16 * 1024) << - " ====\n" - "==== optimistic unchoke: " << sess_stat.optimistic_unchoke_counter - << " unchoke counter: " << sess_stat.unchoke_counter - << " ====" << std::endl; + snprintf(str, sizeof(str), "==== conns: %d down: %s%s%s (%s%s%s) up: %s%s%s (%s%s%s) " + "tcp/ip: %s%s%s %s%s%s DHT: %s%s%s %s%s%s tracker: %s%s%s %s%s%s ====\n" + , sess_stat.num_peers + , esc("32"), add_suffix(sess_stat.download_rate, "/s").c_str(), esc("0") + , esc("32"), add_suffix(sess_stat.total_download).c_str(), esc("0") + , esc("31"), add_suffix(sess_stat.upload_rate, "/s").c_str(), esc("0") + , esc("31"), add_suffix(sess_stat.total_upload).c_str(), esc("0") + , esc("32"), add_suffix(sess_stat.ip_overhead_download_rate, "/s").c_str(), esc("0") + , esc("31"), add_suffix(sess_stat.ip_overhead_upload_rate, "/s").c_str(), esc("0") + , esc("32"), add_suffix(sess_stat.dht_download_rate, "/s").c_str(), esc("0") + , esc("31"), add_suffix(sess_stat.dht_upload_rate, "/s").c_str(), esc("0") + , esc("32"), add_suffix(sess_stat.tracker_download_rate, "/s").c_str(), esc("0") + , esc("31"), add_suffix(sess_stat.tracker_upload_rate, "/s").c_str(), esc("0")); + out += str; + + snprintf(str, sizeof(str), "==== waste: %s fail: %s unchoked: %d / %d " + "bw queues: %8d (%d) | %8d (%d) cache: w: %lld%% r: %lld%% size: %s (%s) / %s ===\n" + , add_suffix(sess_stat.total_redundant_bytes).c_str() + , add_suffix(sess_stat.total_failed_bytes).c_str() + , sess_stat.num_unchoked, sess_stat.allowed_upload_slots + , sess_stat.up_bandwidth_bytes_queue + , sess_stat.up_bandwidth_queue + , sess_stat.down_bandwidth_bytes_queue + , sess_stat.down_bandwidth_queue + , (cs.blocks_written - cs.writes) * 100 / cs.blocks_written + , cs.blocks_read_hit * 100 / cs.blocks_read + , add_suffix(cs.cache_size * 16 * 1024).c_str() + , add_suffix(cs.read_cache_size * 16 * 1024).c_str() + , add_suffix(cs.total_used_buffers * 16 * 1024).c_str()); + out += str; + + snprintf(str, sizeof(str), "==== optimistic unchoke: %d unchoke counter: %d ====\n" + , sess_stat.optimistic_unchoke_counter, sess_stat.unchoke_counter); + out += str; 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; + snprintf(str, sizeof(str), "DHT nodes: %d DHT cached nodes: %d total DHT size: %lld\n" + , sess_stat.dht_nodes, sess_stat.dht_node_cache, sess_stat.dht_global_nodes); + out += str; + 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"; + snprintf(str, sizeof(str), " %s %d (%d) ( timeouts %d responses %d)\n" + , i->type, i->outstanding_requests, i->branch_factor, i->timeouts, i->responses); + out += str; } } @@ -1319,7 +1379,9 @@ int main(int argc, char* argv[]) || print_peers) h.get_peer_info(peers); - out << "====== " << h.name() << " ======" << std::endl; + out += "====== "; + out += h.name(); + out += " ======\n"; if (print_peers && !peers.empty()) print_peer_info(out, peers); @@ -1331,18 +1393,17 @@ int main(int argc, char* argv[]) 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"; + snprintf(str, sizeof(str), "%2d %55s fails: %3d %s %s\n" + , i->tier, i->url.c_str(), i->fails, i->verified?"OK ":"- " + , i->updating?"updating":to_string( + total_seconds(i->next_announce - now), 8).c_str()); + out += str; } } 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)); @@ -1415,9 +1476,10 @@ int main(int argc, char* argv[]) << (total_milliseconds(time_now() - i->last_use) / 1000.f) << "\n"; } - out << "___________________________________\n"; + */ + out += "___________________________________\n"; } - +/* if (print_file_progress && s.state != torrent_status::seeding && h.has_metadata()) @@ -1442,9 +1504,9 @@ int main(int argc, char* argv[]) if (pad_file) out << esc("0"); } - out << "___________________________________\n"; + out += "___________________________________\n"; } - +*/ } if (print_log) @@ -1452,12 +1514,13 @@ int main(int argc, char* argv[]) for (std::deque::iterator i = events.begin(); i != events.end(); ++i) { - out << "\n" << *i; + out += "\n"; + out += *i; } } clear_home(); - puts(out.str().c_str()); + puts(out.c_str()); if (!monitor_dir.empty() && next_dir_scan < time_now()) @@ -1469,24 +1532,24 @@ int main(int argc, char* argv[]) } } - std::cout << "saving session state" << std::endl; + printf("saving session state\n"); { 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); + + std::vector out; + bencode(std::back_inserter(out), session_state); + save_file(".ses_state", out); } #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); + printf("saving DHT state\n"); + entry dht_state = ses.dht_state(); + + std::vector out; + bencode(std::back_inserter(out), dht_state); + save_file(".dht_state", out); #endif - std::cout << "closing session" << std::endl; + printf("closing session"); return 0; } diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index cb0d7598e..2793b591f 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -75,7 +75,7 @@ int main(int argc, char* argv[]) } std::cout << "\n\n----- raw info -----\n\n"; - std::cout << e << std::endl; + std::cout << print_entry(e) << std::endl; error_code ec; torrent_info t(e, ec); @@ -104,7 +104,9 @@ int main(int argc, char* argv[]) 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"; + char ih[41]; + to_hex((char const*)&t.info_hash()[0], 20, ih); + std::cout << "info hash: " << ih << "\n"; std::cout << "comment: " << t.comment() << "\n"; std::cout << "created by: " << t.creator() << "\n"; std::cout << "magnet link: " << make_magnet_uri(t) << "\n"; diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index de7a91877..8213df7ba 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -91,7 +91,12 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_MLOCK 1 #define TORRENT_USE_READV 1 #define TORRENT_USE_WRITEV 1 + +#ifdef TORRENT_DEBUG #define TORRENT_USE_IOSTREAM 1 +#else +#define TORRENT_USE_IOSTREAM 0 +#endif // should wpath or path be used? #if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY \ diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index a07a3fe5a..199e09db9 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -64,6 +64,7 @@ namespace libtorrent std::string const& url, std::string argument); TORRENT_EXPORT std::string to_hex(std::string const& s); + TORRENT_EXPORT bool is_hex(char const *in, int len); TORRENT_EXPORT void to_hex(char const *in, int len, char* out); TORRENT_EXPORT bool from_hex(char const *in, int len, char* out); diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index 80187c4e1..9bea1a225 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -230,6 +230,7 @@ namespace libtorrent char const* m_end; }; + TORRENT_EXPORT std::string print_entry(lazy_entry const& e); #if TORRENT_USE_IOSTREAM TORRENT_EXPORT std::ostream& operator<<(std::ostream& os, lazy_entry const& e); #endif diff --git a/src/escape_string.cpp b/src/escape_string.cpp index 8ec225bd7..44e0a538a 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -434,6 +434,16 @@ namespace libtorrent return -1; } + TORRENT_EXPORT bool is_hex(char const *in, int len) + { + for (char const* end = in + len; in < end; ++in) + { + int t = hex_to_int(*in); + if (t == -1) return false; + } + return true; + } + TORRENT_EXPORT bool from_hex(char const *in, int len, char* out) { for (char const* end = in + len; in < end; ++in, ++out) diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index b9f692467..62e427a1f 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE. #if TORRENT_USE_IOSTREAM #include -#include #endif namespace @@ -369,10 +368,22 @@ namespace libtorrent #if TORRENT_USE_IOSTREAM std::ostream& operator<<(std::ostream& os, lazy_entry const& e) { + return os << print_entry(e); + } +#endif // TORRENT_USE_IOSTREAM + + std::string print_entry(lazy_entry const& e) + { + std::string ret; switch (e.type()) { - case lazy_entry::none_t: return os << "none"; - case lazy_entry::int_t: return os << std::dec << std::setw(0) << e.int_value(); + case lazy_entry::none_t: return "none"; + case lazy_entry::int_t: + { + char str[100]; + snprintf(str, sizeof(str), "%lld", e.int_value()); + return str; + } case lazy_entry::string_t: { bool printable = true; @@ -384,16 +395,25 @@ namespace libtorrent printable = false; break; } - os << "'"; - if (printable) return os << e.string_value() << "'"; + ret += "'"; + if (printable) + { + ret += e.string_value(); + ret += "'"; + return ret; + } for (int i = 0; i < e.string_length(); ++i) - os << std::hex << std::setfill('0') << std::setw(2) - << int((unsigned char)(str[i])); - return os << "'" << std::dec; + { + char str[5]; + snprintf(str, sizeof(str), "%02x", str[i]); + ret += str; + } + ret += "'"; + return ret; } case lazy_entry::list_t: { - os << "["; + ret += '['; bool one_liner = (e.list_size() == 0 || (e.list_at(0)->type() == lazy_entry::int_t && e.list_size() < 20) @@ -401,19 +421,20 @@ namespace libtorrent && (e.list_at(0)->string_length() < 10 || e.list_size() < 2) && e.list_size() < 5)); - if (!one_liner) os << "\n"; + if (!one_liner) ret += "\n"; for (int i = 0; i < e.list_size(); ++i) { - if (i == 0 && one_liner) os << " "; - os << *e.list_at(i); - if (i < e.list_size() - 1) os << (one_liner?", ":",\n"); - else os << (one_liner?" ":"\n"); + if (i == 0 && one_liner) ret += " "; + ret += print_entry(*e.list_at(i)); + if (i < e.list_size() - 1) ret += (one_liner?", ":",\n"); + else ret += (one_liner?" ":"\n"); } - return os << "]"; + ret += "]"; + return ret; } case lazy_entry::dict_t: { - os << "{"; + ret += "{"; bool one_liner = (e.dict_size() == 0 || e.dict_at(0).second->type() == lazy_entry::int_t || (e.dict_at(0).second->type() == lazy_entry::string_t @@ -421,20 +442,23 @@ namespace libtorrent || e.dict_at(0).first.size() < 10) && e.dict_size() < 5; - if (!one_liner) os << "\n"; + if (!one_liner) ret += "\n"; for (int i = 0; i < e.dict_size(); ++i) { - if (i == 0 && one_liner) os << " "; + if (i == 0 && one_liner) ret += " "; std::pair ent = e.dict_at(i); - os << "'" << ent.first << "': " << *ent.second; - if (i < e.dict_size() - 1) os << (one_liner?", ":",\n"); - else os << (one_liner?" ":"\n"); + ret += "'"; + ret += ent.first; + ret += "': "; + ret += print_entry(*ent.second); + if (i < e.dict_size() - 1) ret += (one_liner?", ":",\n"); + else ret += (one_liner?" ":"\n"); } - return os << "}"; + ret += "}"; + return ret; } } - return os; + return ret; } -#endif // TORRENT_USE_IOSTREAM };