*** empty log message ***

This commit is contained in:
Arvid Norberg 2004-01-02 20:46:24 +00:00
parent 5cde50ee01
commit 95026395f3
14 changed files with 281 additions and 90 deletions

View File

@ -203,7 +203,15 @@ int main(int argc, char* argv[])
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
t.print(std::cout);
handles.push_back(ses.add_torrent(t, ""));
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));
handles.push_back(ses.add_torrent(t, "", resume_data));
handles.back().set_max_uploads(40);
}
catch (std::exception& e)
@ -220,7 +228,16 @@ int main(int argc, char* argv[])
char c;
if (sleep_and_input(&c))
{
if (c == 'q') break;
if (c == 'q')
{
std::vector<char> data;
handles.front().write_resume_data(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));
break;
}
}
std::auto_ptr<alert> a;

View File

@ -75,6 +75,44 @@ namespace libtorrent
namespace detail
{
struct session_impl;
// reads an integer from a byte stream
// in big endian byte order and converts
// it to native endianess
template<class InIt>
unsigned int read_uint(InIt& start)
{
unsigned int val = 0;
val |= static_cast<unsigned char>(*start) << 24; ++start;
val |= static_cast<unsigned char>(*start) << 16; ++start;
val |= static_cast<unsigned char>(*start) << 8; ++start;
val |= static_cast<unsigned char>(*start); ++start;
return val;
}
template<class InIt>
inline int read_int(InIt& start)
{
return static_cast<int>(read_uint(start));
}
// reads an integer to a byte stream
// and converts it from native endianess
template<class OutIt>
void write_uint(unsigned int val, OutIt& start)
{
*start = static_cast<unsigned char>((val >> 24) & 0xff); ++start;
*start = static_cast<unsigned char>((val >> 16) & 0xff); ++start;
*start = static_cast<unsigned char>((val >> 8) & 0xff); ++start;
*start = static_cast<unsigned char>((val) & 0xff); ++start;
}
template<class OutIt>
inline void write_int(int val, OutIt& start)
{
write_uint(reinterpret_cast<unsigned int&>(val), start);
}
}
struct protocol_error: std::runtime_error

View File

@ -59,10 +59,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/debug.hpp"
#if defined(_MSC_VER) && !defined(NDEBUG)
#include <eh.h>
#if !defined(NDEBUG) && defined(_MSC_VER)
# include <float.h>
# include <eh.h>
#endif
// TODO: if we're a seed and the peer is a seed, close the connections
@ -75,12 +74,15 @@ namespace libtorrent
// workaround for microsofts
// hardware exceptions that makes
// it hard to debug stuff
#if defined(_MSC_VER) && !defined(NDEBUG)
#if !defined(NDEBUG) && defined(MSC_VER)
struct eh_initializer
{
eh_initializer()
{ ::_set_se_translator(straight_to_debugger); }
{
_clearfp();
_controlfp(_EM_INEXACT | _EM_UNDERFLOW, _MCW_EM );
::_set_se_translator(straight_to_debugger);
}
static void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*)
{ throw; }
@ -100,6 +102,12 @@ namespace libtorrent
sha1_hash info_hash;
void parse_resume_data(
const std::vector<char>* rd
, const torrent_info& info);
std::vector<int> piece_map;
std::vector<piece_picker::downloading_piece> unfinished_pieces;
// is filled in by storage::initialize_pieces()
// and represents the progress. It should be a
// value in the range [0, 1]
@ -206,7 +214,19 @@ namespace libtorrent
// 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);
, 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);
}
void remove_torrent(const torrent_handle& h);
void set_http_settings(const http_settings& s);
@ -219,6 +239,11 @@ 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

@ -231,7 +231,7 @@ namespace libtorrent
, std::vector<boost::shared_ptr<socket> >& writable
, std::vector<boost::shared_ptr<socket> >& error);
int count_read_monitors() const { return m_readable.size(); }
int count_read_monitors() const { return (int)m_readable.size(); }
private:

View File

@ -101,7 +101,8 @@ namespace libtorrent
// fills the vector that maps all allocated
// slots to the piece that is stored (or
// partially stored) there
// partially stored) there. -2 is the index
// of unassigned pieces and -1 is unallocated
void export_piece_map(std::vector<int>& pieces) const;
private:

View File

@ -133,6 +133,8 @@ namespace libtorrent
const torrent_info& get_torrent_info() const;
bool is_valid() const;
void write_resume_data(std::vector<char>& buf);
// TODO: add force reannounce
// TODO: add a feature where the user can ask the torrent

View File

@ -106,7 +106,7 @@ namespace libtorrent
reverse_file_iterator rend_files() const { return m_files.rend(); }
std::size_t num_files() const { return m_files.size(); }
const file& file_at(int index) const { assert(index >= 0 && index < m_files.size()); return m_files[index]; }
const file& file_at(int index) const { assert(index >= 0 && index < (int)m_files.size()); return m_files[index]; }
const std::vector<announce_entry>& trackers() const { return m_urls; }
@ -117,7 +117,7 @@ namespace libtorrent
entry::integer_type total_size() const { return m_total_size; }
entry::integer_type piece_length() const { return m_piece_length; }
std::size_t num_pieces() const { return m_piece_hash.size(); }
int num_pieces() const { return (int)m_piece_hash.size(); }
const sha1_hash& info_hash() const { return m_info_hash; }
const std::string& name() const { return m_name; }
void print(std::ostream& os) const;

View File

@ -46,32 +46,6 @@ POSSIBILITY OF SUCH DAMAGE.
using namespace libtorrent;
namespace
{
// reads an integer from a byte stream
// in big endian byte order and converts
// it to native endianess
unsigned int read_int(const char* buf)
{
unsigned int val = 0;
val |= static_cast<unsigned char>(buf[0]) << 24;
val |= static_cast<unsigned char>(buf[1]) << 16;
val |= static_cast<unsigned char>(buf[2]) << 8;
val |= static_cast<unsigned char>(buf[3]);
return val;
}
void write_int(unsigned int val, char* buf)
{
buf[0] = static_cast<unsigned char>(val >> 24);
buf[1] = static_cast<unsigned char>(val >> 16);
buf[2] = static_cast<unsigned char>(val >> 8);
buf[3] = static_cast<unsigned char>(val);
}
}
libtorrent::peer_connection::peer_connection(
detail::session_impl& ses
, selector& sel
@ -241,8 +215,9 @@ boost::optional<piece_block_progress> libtorrent::peer_connection::downloading_p
|| m_recv_buffer[0] != msg_piece)
return boost::optional<piece_block_progress>();
int piece_index = read_int(&m_recv_buffer[1]);
int offset = read_int(&m_recv_buffer[5]);
const char* ptr = &m_recv_buffer[1];
int piece_index = detail::read_int(ptr);
int offset = detail::read_int(ptr);
int len = m_packet_size - 9;
// is any of the piece message header data invalid?
@ -363,9 +338,10 @@ bool libtorrent::peer_connection::dispatch_message(int received)
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false;
std::size_t index = read_int(&m_recv_buffer[1]);
const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr);
// if we got an invalid message, abort
if (index >= m_have_piece.size())
if (index >= m_have_piece.size() || index < 0)
throw protocol_error("have message with higher index than the number of pieces");
#ifndef NDEBUG
@ -458,9 +434,10 @@ bool libtorrent::peer_connection::dispatch_message(int received)
if (m_recv_pos < m_packet_size) return false;
peer_request r;
r.piece = read_int(&m_recv_buffer[1]);
r.start = read_int(&m_recv_buffer[5]);
r.length = read_int(&m_recv_buffer[9]);
const char* ptr = &m_recv_buffer[1];
r.piece = detail::read_int(ptr);
r.start = detail::read_int(ptr);
r.length = detail::read_int(ptr);
// make sure this request
// is legal and taht the peer
@ -515,7 +492,8 @@ bool libtorrent::peer_connection::dispatch_message(int received)
if (m_recv_pos < m_packet_size) return false;
std::size_t index = read_int(&m_recv_buffer[1]);
const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr);
if (index < 0 || index >= m_torrent->torrent_file().num_pieces())
{
#ifndef NDEBUG
@ -523,7 +501,7 @@ bool libtorrent::peer_connection::dispatch_message(int received)
#endif
throw protocol_error("invalid piece index in piece message");
}
int offset = read_int(&m_recv_buffer[5]);
int offset = detail::read_int(ptr);
int len = m_packet_size - 9;
if (offset < 0)
@ -629,9 +607,10 @@ bool libtorrent::peer_connection::dispatch_message(int received)
if (m_recv_pos < m_packet_size) return false;
peer_request r;
r.piece = read_int(&m_recv_buffer[1]);
r.start = read_int(&m_recv_buffer[5]);
r.length = read_int(&m_recv_buffer[9]);
const char* ptr = &m_recv_buffer[1];
r.piece = detail::read_int(ptr);
r.start = detail::read_int(ptr);
r.length = detail::read_int(ptr);
std::deque<peer_request>::iterator i
= std::find(m_requests.begin(), m_requests.end(), r);
@ -686,21 +665,18 @@ void libtorrent::peer_connection::cancel_block(piece_block block)
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
start_offset += 5;
char* ptr = &m_send_buffer[start_offset];
// index
write_int(block.piece_index, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block.piece_index, ptr);
// begin
write_int(block_offset, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block_offset, ptr);
// length
write_int(block_size, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block_size, ptr);
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> CANCEL [ piece: " << block.piece_index << " | s: " << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
#endif
assert(start_offset == m_send_buffer.size());
send_buffer_updated();
}
@ -728,23 +704,20 @@ void libtorrent::peer_connection::request_block(piece_block block)
m_send_buffer.resize(start_offset + 17);
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
start_offset +=5;
char* ptr = &m_send_buffer[start_offset+5];
// index
write_int(block.piece_index, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block.piece_index, ptr);
// begin
write_int(block_offset, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block_offset, ptr);
// length
write_int(block_size, &m_send_buffer[start_offset]);
start_offset += 4;
detail::write_int(block_size, ptr);
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> REQUEST [ piece: " << block.piece_index << " | s: " << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
#endif
assert(start_offset == m_send_buffer.size());
send_buffer_updated();
}
@ -757,7 +730,8 @@ void libtorrent::peer_connection::send_bitfield()
const int packet_size = (m_have_piece.size() + 7) / 8 + 5;
const int old_size = m_send_buffer.size();
m_send_buffer.resize(old_size + packet_size);
write_int(packet_size - 4, &m_send_buffer[old_size]);
char* ptr = &m_send_buffer[old_size];
detail::write_int(packet_size - 4, ptr);
m_send_buffer[old_size+4] = msg_bitfield;
std::fill(m_send_buffer.begin()+old_size+5, m_send_buffer.end(), 0);
for (std::size_t i = 0; i < m_have_piece.size(); ++i)
@ -821,7 +795,8 @@ void libtorrent::peer_connection::send_have(int index)
{
const int packet_size = 9;
char msg[packet_size] = {0,0,0,5,msg_have};
write_int(index, msg+5);
char* ptr = msg+5;
detail::write_int(index, ptr);
m_send_buffer.insert(m_send_buffer.end(), msg, msg + packet_size);
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> HAVE [ piece: " << index << " ]\n";
@ -1082,12 +1057,14 @@ void libtorrent::peer_connection::receive_data()
case read_packet_size:
{
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) break;
assert(m_recv_pos == m_packet_size);
// convert from big endian to native byte order
m_packet_size = read_int(&m_recv_buffer[0]);
const char* ptr = &m_recv_buffer[0];
m_packet_size = detail::read_int(ptr);
// don't accept packets larger than 1 MB
if (m_packet_size > 1024*1024 || m_packet_size < 0)
{
@ -1112,7 +1089,7 @@ void libtorrent::peer_connection::receive_data()
m_recv_pos = 0;
assert(m_packet_size > 0);
break;
}
case read_packet:
if (dispatch_message(received))
@ -1183,10 +1160,11 @@ void libtorrent::peer_connection::send_data()
const int send_buffer_offset = m_send_buffer.size();
const int packet_size = 4 + 5 + 4 + r.length;
m_send_buffer.resize(send_buffer_offset + packet_size);
write_int(packet_size-4, &m_send_buffer[send_buffer_offset]);
m_send_buffer[send_buffer_offset+4] = msg_piece;
write_int(r.piece, &m_send_buffer[send_buffer_offset+5]);
write_int(r.start, &m_send_buffer[send_buffer_offset+9]);
char* ptr = &m_send_buffer[send_buffer_offset];
detail::write_int(packet_size-4, ptr);
*ptr = msg_piece; ++ptr;
detail::write_int(r.piece, ptr);
detail::write_int(r.start, ptr);
m_torrent->filesystem().read(
&m_send_buffer[send_buffer_offset+13]

View File

@ -87,6 +87,7 @@ namespace
}
}
assert(false);
return piece_block(-1, -1);
}
void request_a_block(torrent& t, peer_connection& c)

View File

@ -746,9 +746,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(
torrent_handle session::add_torrent_impl(
const torrent_info& ti
, const boost::filesystem::path& save_path)
, const boost::filesystem::path& save_path
, const std::vector<char>* resume_data)
{
{
@ -772,13 +773,15 @@ namespace libtorrent
// create the torrent and the data associated with
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(new torrent(m_impl, ti, save_path));
boost::shared_ptr<torrent> torrent_ptr(
new torrent(m_impl, ti, save_path));
detail::piece_checker_data d;
d.torrent_ptr = torrent_ptr;
d.save_path = save_path;
d.info_hash = ti.info_hash();
d.parse_resume_data(resume_data, torrent_ptr->torrent_file());
// lock the checker thread
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
@ -877,4 +880,66 @@ namespace libtorrent
m_impl.m_alerts.set_severity(s);
}
void detail::piece_checker_data::parse_resume_data(
const std::vector<char>* rd
, const torrent_info& info)
{
piece_map.clear();
unfinished_pieces.clear();
std::vector<int> tmp_pieces;
std::vector<piece_picker::downloading_piece> tmp_unfinished;
if (rd == 0) return;
const std::vector<char>& data = *rd;
if (data.size() < 3 * 4) return;
std::vector<char>::const_iterator ptr = data.begin();
int num_slots = detail::read_int(ptr);
if (num_slots < 0) return;
if (data.size() < (3 + num_slots) * 4) return;
tmp_pieces.reserve(num_slots);
for (int i = 0; i < num_slots; ++i)
{
int index = read_int(ptr);
if (index >= info.num_pieces() || index < -2)
return;
tmp_pieces.push_back(index);
}
int num_blocks_per_piece = read_int(ptr);
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 0)
return;
int num_unfinished = read_int(ptr);
if (num_unfinished < 0) return;
if (data.size() != (3 + num_slots + 1 + num_unfinished) * 4)
return;
tmp_unfinished.reserve(num_unfinished);
for (int i = 0; i < num_unfinished; ++i)
{
piece_picker::downloading_piece p;
p.index = detail::read_int(ptr);
p.finished_blocks.reset();
p.requested_blocks.reset();
if (p.index < 0
|| p.index >= info.num_pieces())
return;
for (int j = 0; j < num_blocks_per_piece / 32; ++j)
{
unsigned int bits = read_int(ptr);
for (int k = 0; k < 32; ++k) p.finished_blocks[j * 32 + k] = true;
}
tmp_unfinished.push_back(p);
}
piece_map.swap(tmp_pieces);
unfinished_pieces.swap(tmp_unfinished);
}
}

View File

@ -105,10 +105,6 @@ namespace {
}
// TODO: implement fast resume. i.e. the possibility to
// supply additional information about which pieces are
// assigned to which slots.
namespace libtorrent {
struct thread_safe_storage

View File

@ -128,7 +128,7 @@ namespace
for (int i = 0; i < len; ++i)
{
if (std::isalnum(static_cast<unsigned char>(*str))
|| std::find(
|| std::count(
special_chars
, special_chars+sizeof(special_chars)-1
, *str))

View File

@ -51,16 +51,19 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/hasher.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/session.hpp"
// TODO: peer_connection is only used because of detail::write_int
// and detail::read_int, they should probably be moved to a common
// header.
#include "libtorrent/peer_connection.hpp"
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
using ::srand;
using ::isprint;
using ::isalnum;
};
#endif
namespace libtorrent
{
@ -167,6 +170,71 @@ namespace libtorrent
return false;
}
void torrent_handle::write_resume_data(std::vector<char>& buf)
{
buf.clear();
std::vector<int> piece_index;
if (m_ses == 0) return;
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) return;
t->filesystem().export_piece_map(piece_index);
std::back_insert_iterator<std::vector<char> > out(buf);
// TODO: write file header
// TODO: write info hash
// 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());
}
const piece_picker& p = t->picker();
const std::vector<piece_picker::downloading_piece>& q
= p.get_download_queue();
// blocks per piece
int num_blocks_per_piece =
t->torrent_file().piece_length() / t->block_size();
detail::write_int(num_blocks_per_piece, out);
// num unfinished pieces
int num_unfinished = q.size();
detail::write_int(num_unfinished, out);
// info for each unfinished piece
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin();
i != q.end();
++i)
{
// the unsinished piece's index
detail::write_int(i->index, out);
// write
for (int j = 0; j < num_blocks_per_piece / 32; ++j)
{
unsigned int v = 0;
for (int k = 0; k < 32; ++k) v |= i->finished_blocks[j*32+k]?(1 << k):0;
detail::write_int(v, out);
}
}
}
boost::filesystem::path torrent_handle::save_path() const
{
if (m_ses == 0) throw invalid_handle();

View File

@ -99,7 +99,7 @@ namespace libtorrent
for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k)
{
announce_entry e;
e.tier = j - l.begin();
e.tier = (int)(j - l.begin());
e.url = k->string();
m_urls.push_back(e);
}
@ -235,7 +235,7 @@ namespace libtorrent
int torrent_info::prioritize_tracker(int index)
{
if (index > m_urls.size()) return m_urls.size()-1;
if (index > (int)m_urls.size()) return (int)m_urls.size()-1;
while (index > 0 && m_urls[index].tier == m_urls[index-1].tier)
{