forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
2274c82c61
commit
91c9156de1
1157
docs/index.html
1157
docs/index.html
File diff suppressed because it is too large
Load Diff
1235
docs/index.rst
1235
docs/index.rst
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
272
src/entry.cpp
272
src/entry.cpp
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue