*** empty log message ***

This commit is contained in:
Arvid Norberg 2004-01-07 00:48:02 +00:00
parent 2274c82c61
commit 91c9156de1
18 changed files with 3053 additions and 2569 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
docs/libtorrent_screen.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

1264
docs/manual.html Executable file

File diff suppressed because it is too large Load Diff

1353
docs/manual.rst Executable file

File diff suppressed because it is too large Load Diff

View File

@ -206,10 +206,8 @@ int main(int argc, char* argv[])
std::ifstream resume_file("test.fastresume", std::ios_base::binary);
resume_file.unsetf(std::ios_base::skipws);
std::vector<char> resume_data;
std::copy(std::istream_iterator<char>(resume_file)
, std::istream_iterator<char>()
, std::back_inserter(resume_data));
entry resume_data = bdecode(std::istream_iterator<char>(resume_file)
, std::istream_iterator<char>());
handles.push_back(ses.add_torrent(t, "", resume_data));
handles.back().set_max_uploads(40);
@ -230,12 +228,11 @@ int main(int argc, char* argv[])
{
if (c == 'q')
{
std::vector<char> data;
handles.front().write_resume_data(data);
entry data = handles.front().write_resume_data();
std::ofstream out("test.fastresume", std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
std::copy(data.begin(), data.end(), std::ostream_iterator<char>(out));
bencode(std::ostream_iterator<char>(out), data);
break;
}
}
@ -313,8 +310,7 @@ int main(int argc, char* argv[])
<< "(" << add_suffix(i->total_download) << ") "
<< "u: " << add_suffix(i->up_speed) << "/s "
<< "(" << add_suffix(i->total_upload) << ") "
// << "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " "
<< "q: " << i->download_queue_length << " "
<< "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " "
<< "f: "
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")
@ -336,13 +332,8 @@ int main(int argc, char* argv[])
if (progress > j) out << "#";
else out << "-";
}
out << " ";
out << "\n";
}
else
{
for (int i = 0; i < 19; ++i) out << " ";
}
out << identify_client(i->id) << "\n";
}
out << "___________________________________\n";

View File

@ -55,7 +55,6 @@ int main(int argc, char* argv[])
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
@ -63,6 +62,8 @@ int main(int argc, char* argv[])
e.print(std::cout);
torrent_info t(e);
// print info about torrent
std::cout << "\n\n----- torrent file info -----\n\n";
std::cout << "trackers:\n";

View File

@ -51,7 +51,7 @@ namespace libtorrent {
class alert
{
public:
enum severity_t { debug, info, warning, critital, fatal, none };
enum severity_t { debug, info, warning, critical, fatal, none };
alert(severity_t severity, const std::string& msg)
: m_msg(msg)

View File

@ -129,6 +129,11 @@ namespace libtorrent
data_type type() const { return m_type; }
entry(const dictionary_type&);
entry(const string_type&);
entry(const list_type&);
entry(const integer_type&);
entry(): m_type(undefined_t) {}
entry(data_type t): m_type(t) { construct(t); }
entry(const entry& e) { copy(e); }
@ -140,6 +145,11 @@ namespace libtorrent
copy(e);
}
void operator=(const dictionary_type&);
void operator=(const string_type&);
void operator=(const list_type&);
void operator=(const integer_type&);
integer_type& integer()
{
if (m_type != int_t) throw type_error("invalid typ requested from entry");

View File

@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
#include <vector>
#include <deque>
#include <string>
#include <boost/smart_ptr.hpp>
#include <boost/noncopyable.hpp>
@ -50,6 +51,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/debug.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
// TODO: each time a block is 'taken over'
// from another peer. That peer must be given
@ -135,6 +138,23 @@ namespace libtorrent
protocol_error(const std::string& msg): std::runtime_error(msg) {};
};
struct chat_message_alert: alert
{
chat_message_alert(const torrent_handle& h
, const peer_id& send
, const std::string& msg)
: alert(alert::critical, msg)
, handle(h)
, sender(send)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new chat_message_alert(*this)); }
torrent_handle handle;
peer_id sender;
};
struct peer_request
{
int piece;
@ -336,6 +356,7 @@ namespace libtorrent
void send_have(int index);
void send_handshake();
void send_extensions();
void send_chat_message(const std::string& msg);
// is used during handshake
enum state
@ -519,7 +540,7 @@ namespace libtorrent
enum extension_index
{
gzip_piece,
extended_chat_message,
num_supported_extensions
};
static const char* extension_names[num_supported_extensions];

View File

@ -116,7 +116,7 @@ namespace libtorrent
sha1_hash info_hash;
void parse_resume_data(
const std::vector<char>* rd
const entry& rd
, const torrent_info& info);
std::vector<int> piece_map;
std::vector<piece_picker::downloading_piece> unfinished_pieces;
@ -225,20 +225,10 @@ namespace libtorrent
~session();
// all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent(
const torrent_info& ti
, const boost::filesystem::path& save_path)
{
return add_torrent_impl(ti, save_path, 0);
}
torrent_handle add_torrent(
const torrent_info& ti
, const boost::filesystem::path& save_path
, const std::vector<char>& resume_data)
{
return add_torrent_impl(ti, save_path, &resume_data);
}
, const entry& resume_data = entry());
void remove_torrent(const torrent_handle& h);
@ -252,11 +242,6 @@ namespace libtorrent
private:
torrent_handle add_torrent_impl(
const torrent_info& ti
, const boost::filesystem::path& save_path
, const std::vector<char>* resume_data);
// data shared between the main thread
// and the working thread
detail::session_impl m_impl;

View File

@ -247,6 +247,9 @@ namespace libtorrent
boost::filesystem::path save_path() const
{ return m_storage.save_path(); }
alert_manager& alerts() const;
torrent_handle get_handle() const;
// DEBUG
#ifndef NDEBUG
logger* spawn_logger(const char* title);

View File

@ -133,7 +133,7 @@ namespace libtorrent
const torrent_info& get_torrent_info() const;
bool is_valid() const;
void write_resume_data(std::vector<char>& buf);
entry write_resume_data();
// TODO: add force reannounce

View File

@ -49,127 +49,183 @@ namespace
}
}
void libtorrent::entry::construct(data_type t)
namespace libtorrent
{
m_type = t;
switch(m_type)
{
case int_t:
new(data) integer_type;
break;
case string_t:
new(data) string_type;
break;
case list_t:
new(data) list_type;
break;
case dictionary_t:
new (data) dictionary_type;
break;
default:
m_type = undefined_t;
}
}
void libtorrent::entry::copy(const entry& e)
{
m_type = e.m_type;
switch(m_type)
entry::entry(const dictionary_type& v)
{
case int_t:
new(data) integer_type(e.integer());
break;
case string_t:
new(data) string_type(e.string());
break;
case list_t:
new(data) list_type(e.list());
break;
case dictionary_t:
new (data) dictionary_type(e.dict());
break;
default:
m_type = undefined_t;
new(data) dictionary_type(v);
m_type = dictionary_t;
}
}
void libtorrent::entry::destruct()
{
switch(m_type)
entry::entry(const string_type& v)
{
case int_t:
call_destructor(reinterpret_cast<integer_type*>(data));
break;
case string_t:
call_destructor(reinterpret_cast<string_type*>(data));
break;
case list_t:
call_destructor(reinterpret_cast<list_type*>(data));
break;
case dictionary_t:
call_destructor(reinterpret_cast<dictionary_type*>(data));
break;
default:
break;
new(data) string_type(v);
m_type = string_t;
}
}
void libtorrent::entry::print(std::ostream& os, int indent) const
{
for (int i = 0; i < indent; ++i) os << " ";
switch (m_type)
entry::entry(const list_type& v)
{
case int_t:
os << integer() << "\n";
break;
case string_t:
new(data) list_type(v);
m_type = list_t;
}
entry::entry(const integer_type& v)
{
new(data) integer_type(v);
m_type = int_t;
}
void entry::operator=(const dictionary_type& v)
{
destruct();
new(data) dictionary_type(v);
m_type = dictionary_t;
}
void entry::operator=(const string_type& v)
{
destruct();
new(data) string_type(v);
m_type = string_t;
}
void entry::operator=(const list_type& v)
{
destruct();
new(data) list_type(v);
m_type = list_t;
}
void entry::operator=(const integer_type& v)
{
destruct();
new(data) integer_type(v);
m_type = int_t;
}
void entry::construct(data_type t)
{
m_type = t;
switch(m_type)
{
bool binary_string = false;
for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
case int_t:
new(data) integer_type;
break;
case string_t:
new(data) string_type;
break;
case list_t:
new(data) list_type;
break;
case dictionary_t:
new (data) dictionary_type;
break;
default:
m_type = undefined_t;
}
}
void entry::copy(const entry& e)
{
m_type = e.m_type;
switch(m_type)
{
case int_t:
new(data) integer_type(e.integer());
break;
case string_t:
new(data) string_type(e.string());
break;
case list_t:
new(data) list_type(e.list());
break;
case dictionary_t:
new (data) dictionary_type(e.dict());
break;
default:
m_type = undefined_t;
}
}
void entry::destruct()
{
switch(m_type)
{
case int_t:
call_destructor(reinterpret_cast<integer_type*>(data));
break;
case string_t:
call_destructor(reinterpret_cast<string_type*>(data));
break;
case list_t:
call_destructor(reinterpret_cast<list_type*>(data));
break;
case dictionary_t:
call_destructor(reinterpret_cast<dictionary_type*>(data));
break;
default:
break;
}
}
void entry::print(std::ostream& os, int indent) const
{
for (int i = 0; i < indent; ++i) os << " ";
switch (m_type)
{
case int_t:
os << integer() << "\n";
break;
case string_t:
{
if (!std::isprint(static_cast<unsigned char>(*i)))
{
binary_string = true;
break;
}
}
if (binary_string)
{
os.unsetf(std::ios_base::dec);
os.setf(std::ios_base::hex);
bool binary_string = false;
for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
os << static_cast<unsigned int>((unsigned char)*i);
os.unsetf(std::ios_base::hex);
os.setf(std::ios_base::dec);
os << "\n";
}
else
{
if (!std::isprint(static_cast<unsigned char>(*i)))
{
binary_string = true;
break;
}
}
if (binary_string)
{
os.unsetf(std::ios_base::dec);
os.setf(std::ios_base::hex);
for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
os << static_cast<unsigned int>((unsigned char)*i);
os.unsetf(std::ios_base::hex);
os.setf(std::ios_base::dec);
os << "\n";
}
else
{
os << string() << "\n";
}
} break;
case list_t:
{
os << string() << "\n";
}
} break;
case list_t:
{
os << "list\n";
for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
os << "list\n";
for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
{
i->print(os, indent+1);
}
} break;
case dictionary_t:
{
i->print(os, indent+1);
}
} break;
case dictionary_t:
{
os << "dictionary\n";
for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
{
for (int j = 0; j < indent+1; ++j) os << " ";
os << "[" << i->first << "]";
if (i->second.type() != entry::string_t && i->second.type() != entry::int_t) os << "\n";
else os << " ";
i->second.print(os, indent+2);
}
} break;
default:
os << "<uninitialized>\n";
os << "dictionary\n";
for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
{
for (int j = 0; j < indent+1; ++j) os << " ";
os << "[" << i->first << "]";
if (i->second.type() != entry::string_t && i->second.type() != entry::int_t) os << "\n";
else os << " ";
i->second.print(os, indent+2);
}
} break;
default:
os << "<uninitialized>\n";
}
}
}

View File

@ -52,7 +52,7 @@ namespace libtorrent
// the names of the extensions to look for in
// the extensions-message
const char* peer_connection::extension_names[] =
{ "gzip" };
{ "chat" };
const peer_connection::message_handler peer_connection::m_message_handler[] =
{
@ -728,7 +728,57 @@ namespace libtorrent
void peer_connection::on_extended(int received)
{
m_statistics.received_bytes(0, received);
if (m_packet_size < 5)
throw protocol_error("'extended' message smaller than 5 bytes");
if (m_torrent == 0)
throw protocol_error("'extended' message sent before proper handshake");
if (m_recv_pos < 5) return;
const char* ptr = &m_recv_buffer[1];
int extended_id = detail::read_int(ptr);
switch (extended_id)
{
case extended_chat_message:
{
if (m_packet_size > 2 * 1024)
if (m_recv_pos < m_packet_size) return;
throw protocol_error("CHAT message larger than 2 kB");
try
{
entry d = bdecode(m_recv_buffer.begin()+5, m_recv_buffer.end());
entry::dictionary_type::const_iterator i = d.dict().find("msg");
if (i == d.dict().end())
throw protocol_error("CHAT message did not contain any 'msg'");
const std::string& str = i->second.string();
if (m_torrent->alerts().should_post(alert::critical))
{
m_torrent->alerts()
.post_alert(chat_message_alert(m_torrent->get_handle(), m_peer_id, str));
}
}
catch (invalid_encoding& e)
{
throw protocol_error("invalid bencoding in CHAT message");
}
catch (type_error& e)
{
throw protocol_error("invalid types in bencoded CHAT message");
}
return;
}
default:
throw protocol_error("unknown extended message id");
};
}
@ -746,6 +796,7 @@ namespace libtorrent
{
assert(m_recv_pos >= received);
assert(m_recv_pos > 0);
assert(m_torrent);
int packet_type = m_recv_buffer[0];
if (packet_type < 0
@ -853,6 +904,25 @@ namespace libtorrent
send_buffer_updated();
}
void peer_connection::send_chat_message(const std::string& msg)
{
assert(msg.length() <= 1 * 1024);
if (m_extension_messages[extended_chat_message] == 0) return;
entry e(entry::dictionary_t);
e.dict()["msg"] = msg;
std::vector<char> message;
bencode(std::back_inserter(message), e);
std::back_insert_iterator<std::vector<char> > ptr(m_send_buffer);
detail::write_uint(1 + 4 + message.size(), ptr);
detail::write_uchar(msg_extended, ptr);
detail::write_int(m_extension_messages[extended_chat_message], ptr);
std::copy(message.begin(), message.end(), ptr);
send_buffer_updated();
}
void peer_connection::send_bitfield()
{
#ifndef NDEBUG
@ -884,9 +954,7 @@ namespace libtorrent
for (int i = 0; i < num_supported_extensions; ++i)
{
entry msg_index(entry::int_t);
msg_index.integer() = i;
extension_list.dict()[extension_names[i]] = msg_index;
extension_list.dict()[extension_names[i]] = i;
}
// make room for message size

View File

@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/entry.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/entry.hpp"
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
@ -751,10 +752,10 @@ namespace libtorrent
// TODO: add a check to see if filenames are accepted on the
// current platform.
// if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent_impl(
torrent_handle session::add_torrent(
const torrent_info& ti
, const boost::filesystem::path& save_path
, const std::vector<char>* resume_data)
, const entry& resume_data)
{
{
@ -886,6 +887,97 @@ namespace libtorrent
}
// TODO: store resume data as an entry instead
void detail::piece_checker_data::parse_resume_data(
const entry& resume_data
, const torrent_info& info)
{
// if we don't have any resume data, return
if (resume_data.type() == entry::undefined_t) return;
std::vector<int> tmp_pieces;
std::vector<piece_picker::downloading_piece> tmp_unfinished;
entry rd = resume_data;
try
{
if (rd.dict()["file-format"].string() != "libtorrent resume file")
return;
if (rd.dict()["file-version"].integer() != 1)
return;
// verify info_hash
const std::string &hash = rd.dict()["info-hash"].string();
std::string real_hash(info.info_hash().begin(), info.info_hash().end());
if (hash != real_hash)
return;
// read piece map
const entry::list_type& slots = rd.dict()["slots"].list();
if (slots.size() > info.num_pieces())
return;
tmp_pieces.reserve(slots.size());
for (entry::list_type::const_iterator i = slots.begin();
i != slots.end();
++i)
{
int index = i->integer();
if (index >= info.num_pieces() || index < -2)
return;
tmp_pieces.push_back(index);
}
int num_blocks_per_piece = rd.dict()["blocks per piece"].integer();
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
return;
const entry::list_type& unfinished = rd.dict()["unfinished"].list();
tmp_unfinished.reserve(unfinished.size());
for (entry::list_type::const_iterator i = unfinished.begin();
i != unfinished.end();
++i)
{
piece_picker::downloading_piece p;
if (i->list().size() < 2) return;
p.index = i->list()[0].integer();
if (p.index < 0 || p.index >= info.num_pieces())
return;
const std::string& bitmask = i->list()[1].string();
const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1);
if (bitmask.size() != num_bitmask_bytes) return;
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char bits = bitmask[j];
for (int k = 0; k < 8; ++k)
{
const int bit = j * 8 + k;
if (bits & (1 << k))
p.finished_blocks[bit] = true;
}
}
tmp_unfinished.push_back(p);
}
piece_map.swap(tmp_pieces);
unfinished_pieces.swap(tmp_unfinished);
}
catch (invalid_encoding)
{
return;
}
catch (type_error)
{
return;
}
}
/*
void detail::piece_checker_data::parse_resume_data(
const std::vector<char>* rd
, const torrent_info& info)
@ -958,4 +1050,5 @@ namespace libtorrent
piece_map.swap(tmp_pieces);
unfinished_pieces.swap(tmp_unfinished);
}
*/
}

View File

@ -303,8 +303,7 @@ namespace libtorrent
{
std::stringstream s;
s << "hash for piece " << index << " failed";
torrent_handle self(&m_ses, 0, m_torrent_file.info_hash());
m_ses.m_alerts.post_alert(hash_failed_alert(self, index, s.str()));
m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str()));
}
std::vector<peer_id> downloaders;
m_picker.get_downloaders(downloaders, index);
@ -577,6 +576,18 @@ namespace libtorrent
#endif
}
alert_manager& torrent::alerts() const
{
return m_ses.m_alerts;
}
torrent_handle torrent::get_handle() const
{
return torrent_handle(&m_ses, 0, m_torrent_file.info_hash());
}
#ifndef NDEBUG
void torrent::check_invariant()
{
@ -699,8 +710,7 @@ namespace libtorrent
s << "tracker: \""
<< m_torrent_file.trackers()[m_currently_trying_tracker].url
<< "\" timed out";
torrent_handle self(&m_ses, 0, m_torrent_file.info_hash());
m_ses.m_alerts.post_alert(tracker_alert(self, s.str()));
m_ses.m_alerts.post_alert(tracker_alert(get_handle(), s.str()));
}
// TODO: increase the retry_delay for
// each failed attempt on the same tracker!
@ -726,8 +736,7 @@ namespace libtorrent
s << "tracker: \""
<< m_torrent_file.trackers()[m_currently_trying_tracker].url
<< "\" " << str;
torrent_handle self(&m_ses, 0, m_torrent_file.info_hash());
m_ses.m_alerts.post_alert(tracker_alert(self, s.str()));
m_ses.m_alerts.post_alert(tracker_alert(get_handle(), s.str()));
}

View File

@ -170,43 +170,30 @@ namespace libtorrent
return false;
}
void torrent_handle::write_resume_data(std::vector<char>& buf)
entry torrent_handle::write_resume_data()
{
buf.clear();
std::vector<int> piece_index;
if (m_ses == 0) return;
if (m_ses == 0)
throw invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) return;
if (t == 0)
throw invalid_handle();
t->filesystem().export_piece_map(piece_index);
std::back_insert_iterator<std::vector<char> > out(buf);
entry ret(entry::dictionary_t);
// TODO: write file header
// TODO: write modification-dates for all files
ret.dict()["file-format"] = "libtorrent resume file";
ret.dict()["file-version"] = 1;
for (sha1_hash::const_iterator i = m_info_hash.begin();
i != m_info_hash.end();
++i)
{
detail::write_uchar(*i, out);
}
const sha1_hash& info_hash = t->torrent_file().info_hash();
ret.dict()["info-hash"] = std::string(info_hash.begin(), info_hash.end());
// number of slots
int num_slots = piece_index.size();
detail::write_int(num_slots, out);
// the piece indices for each slot (-1 means no index assigned)
for (std::vector<int>::iterator i = piece_index.begin();
i != piece_index.end();
++i)
{
detail::write_int(*i, out);
assert(*i >= -2);
assert(*i < t->torrent_file().num_pieces());
}
ret.dict()["slots"] = entry(entry::list_t);
entry::list_type& slots = ret.dict()["slots"].list();
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
const piece_picker& p = t->picker();
@ -216,11 +203,12 @@ namespace libtorrent
// blocks per piece
int num_blocks_per_piece =
t->torrent_file().piece_length() / t->block_size();
detail::write_int(num_blocks_per_piece, out);
ret.dict()["blocks per piece"] = num_blocks_per_piece;
// num unfinished pieces
int num_unfinished = q.size();
detail::write_int(num_unfinished, out);
ret.dict()["unfinished"] = entry(entry::list_t);
entry::list_type& up = ret.dict()["unfinished"].list();
// info for each unfinished piece
for (std::vector<piece_picker::downloading_piece>::const_iterator i
@ -228,20 +216,28 @@ namespace libtorrent
i != q.end();
++i)
{
// the unsinished piece's index
detail::write_int(i->index, out);
entry piece_struct(entry::list_t);
// TODO: write the bitmask in correct byteorder
// TODO: make sure to read it in the correct order too
// the unfinished piece's index
piece_struct.list().push_back(i->index);
std::string bitmask;
const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1);
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char v = 0;
for (int k = 0; k < 8; ++k)
v |= i->finished_blocks[j*8+k]?(1 << k):0;
detail::write_uchar(v, out);
bitmask.push_back(v);
}
piece_struct.list().push_back(bitmask);
// TODO: add a hash to piece_struct
// push the struct onto the unfinished-piece list
up.push_back(piece_struct);
}
return ret;
}