2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2003, Arvid Norberg
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef TORRENT_TORRENT_HPP_INCLUDE
|
|
|
|
#define TORRENT_TORRENT_HPP_INCLUDE
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
#include <set>
|
|
|
|
#include <list>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <boost/limits.hpp>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
2003-11-20 20:58:29 +01:00
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-10-26 18:35:23 +01:00
|
|
|
#include "libtorrent/torrent_handle.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/torrent_info.hpp"
|
|
|
|
#include "libtorrent/socket.hpp"
|
|
|
|
#include "libtorrent/policy.hpp"
|
|
|
|
#include "libtorrent/storage.hpp"
|
|
|
|
#include "libtorrent/url_handler.hpp"
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
struct logger;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
struct session_impl;
|
|
|
|
}
|
|
|
|
|
2003-10-23 18:55:52 +02:00
|
|
|
// TODO: each torrent should have a status value that
|
2003-10-23 01:00:57 +02:00
|
|
|
// reflects what's happening to it
|
|
|
|
// TODO: There should be a maximum number of peers that
|
|
|
|
// is maintained (if someone disconnects, try to connect to
|
|
|
|
// anotherone). There should also be a candidate slot where a
|
|
|
|
// new peer is tried for one minute, and if it has better ownload
|
|
|
|
// speed than one of the peers currently connected, it will be
|
|
|
|
// replaced to maximize bandwidth usage. It wil also have to
|
|
|
|
// depend on how many and which pieces the peers have.
|
2003-10-23 18:55:52 +02:00
|
|
|
// TODO: In debug mode all pieces that are sent should be checked.
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
// a torrent is a class that holds information
|
|
|
|
// for a specific download. It updates itself against
|
|
|
|
// the tracker
|
|
|
|
class torrent: public request_callback
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
torrent(detail::session_impl* ses, const torrent_info& torrent_file);
|
2003-10-27 16:43:33 +01:00
|
|
|
~torrent() {}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
void abort() { m_abort = true; m_event = event_stopped; }
|
|
|
|
bool is_aborted() const { return m_abort; }
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
// is called every second by session.
|
|
|
|
void second_tick();
|
|
|
|
|
2003-10-27 16:43:33 +01:00
|
|
|
// returns true if it time for this torrent to make another
|
|
|
|
// tracker request
|
2003-10-23 01:00:57 +02:00
|
|
|
bool should_request() const throw()
|
|
|
|
{
|
2003-11-26 15:11:25 +01:00
|
|
|
// boost::posix_time::time_duration d = m_next_request - boost::posix_time::second_clock::local_time();
|
|
|
|
// return d.is_negative();
|
|
|
|
return m_next_request < boost::posix_time::second_clock::local_time();
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void print(std::ostream& os) const;
|
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
void allocate_files(detail::piece_checker_data* data,
|
2003-10-31 11:56:03 +01:00
|
|
|
boost::mutex& mutex,
|
2003-11-07 02:44:30 +01:00
|
|
|
const boost::filesystem::path& save_path);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
void uploaded_bytes(int num_bytes) { assert(num_bytes > 0); m_bytes_uploaded += num_bytes; }
|
|
|
|
void downloaded_bytes(int num_bytes) { assert(num_bytes > 0); m_bytes_downloaded += num_bytes; }
|
|
|
|
|
|
|
|
int bytes_downloaded() const { return m_bytes_downloaded; }
|
|
|
|
int bytes_uploaded() const { return m_bytes_uploaded; }
|
2003-12-07 02:26:57 +01:00
|
|
|
int bytes_left() const
|
|
|
|
{
|
|
|
|
const std::vector<bool>& p = m_storage.pieces();
|
|
|
|
int num_pieces = std::accumulate(p.begin(), p.end(), 0);
|
|
|
|
int total_blocks
|
|
|
|
= (m_torrent_file.total_size()+m_block_size-1)/m_block_size;
|
|
|
|
int blocks_per_piece
|
|
|
|
= m_torrent_file.piece_length() / m_block_size;
|
|
|
|
int unverified_blocks = m_picker.unverified_blocks();
|
|
|
|
int blocks_we_have = num_pieces * blocks_per_piece;
|
|
|
|
const int last_piece = m_torrent_file.num_pieces()-1;
|
|
|
|
if (p[last_piece])
|
|
|
|
{
|
|
|
|
blocks_we_have += m_picker.blocks_in_piece(last_piece)
|
|
|
|
- blocks_per_piece;
|
|
|
|
}
|
|
|
|
return m_torrent_file.total_size()
|
|
|
|
- (blocks_we_have + unverified_blocks) * m_block_size;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
torrent_status status() const;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
boost::weak_ptr<peer_connection> connect_to_peer(
|
|
|
|
const address& a
|
|
|
|
, const peer_id& id);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
const torrent_info& torrent_file() const throw()
|
|
|
|
{ return m_torrent_file; }
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
policy& get_policy() { return *m_policy; }
|
|
|
|
storage* filesystem() { return &m_storage; }
|
|
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------
|
|
|
|
// PEER MANAGEMENT
|
|
|
|
|
|
|
|
// used by peer_connection to attach itself to a torrent
|
|
|
|
// since incoming connections don't know what torrent
|
|
|
|
// they're a part of until they have received an info_hash.
|
2003-12-01 06:01:40 +01:00
|
|
|
void attach_peer(peer_connection* p);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
// this will remove the peer and make sure all
|
|
|
|
// the pieces it had have their reference counter
|
|
|
|
// decreased in the piece_picker
|
|
|
|
void remove_peer(peer_connection* p);
|
|
|
|
|
|
|
|
// the number of peers that belong to this torrent
|
|
|
|
int num_peers() const { return m_connections.size(); }
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
// returns true if this torrent has a connection
|
|
|
|
// to a peer with the given peer_id
|
|
|
|
bool has_peer(const peer_id& id) const;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-11-05 00:27:06 +01:00
|
|
|
typedef std::vector<peer_connection*>::iterator peer_iterator;
|
|
|
|
typedef std::vector<peer_connection*>::const_iterator peer_const_iterator;
|
|
|
|
|
|
|
|
peer_const_iterator begin() const { return m_connections.begin(); }
|
|
|
|
peer_const_iterator end() const { return m_connections.end(); }
|
|
|
|
|
|
|
|
peer_iterator begin() { return m_connections.begin(); }
|
|
|
|
peer_iterator end() { return m_connections.end(); }
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------
|
|
|
|
// TRACKER MANAGEMENT
|
|
|
|
|
|
|
|
// this is a callback called by the tracker_connection class
|
|
|
|
// when this torrent got a response from its tracker request
|
|
|
|
void tracker_response(const entry& e);
|
|
|
|
|
|
|
|
void tracker_request_timed_out()
|
|
|
|
{
|
2003-11-23 04:00:45 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
debug_log("*** tracker timed out");
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
try_next_tracker();
|
|
|
|
}
|
|
|
|
|
|
|
|
void tracker_request_error(const char* str)
|
|
|
|
{
|
2003-11-23 04:00:45 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
debug_log(std::string("*** tracker error: ") + str);
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
try_next_tracker();
|
|
|
|
}
|
|
|
|
|
|
|
|
// generates a request string for sending
|
|
|
|
// to the tracker
|
|
|
|
std::string generate_tracker_request(int port);
|
|
|
|
|
2003-11-05 00:27:06 +01:00
|
|
|
boost::posix_time::ptime next_announce() const
|
|
|
|
{ return m_next_request; }
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
// --------------------------------------------
|
|
|
|
// PIECE MANAGEMENT
|
|
|
|
|
|
|
|
// returns true if we have downloaded the given piece
|
|
|
|
bool have_piece(unsigned int index) const { return m_storage.have_piece(index); }
|
|
|
|
|
|
|
|
// when we get a have- or bitfield- messages, this is called for every
|
|
|
|
// piece a peer has gained.
|
|
|
|
// returns true if this piece is interesting (i.e. if we would like to download it)
|
|
|
|
bool peer_has(int index)
|
|
|
|
{
|
|
|
|
return m_picker.inc_refcount(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// when peer disconnects, this is called for every piece it had
|
|
|
|
void peer_lost(int index)
|
|
|
|
{
|
|
|
|
m_picker.dec_refcount(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int block_size() const { return m_block_size; }
|
|
|
|
|
|
|
|
// this will tell all peers that we just got his piece
|
|
|
|
// and also let the piece picker know that we have this piece
|
|
|
|
// so it wont pick it for download
|
|
|
|
void announce_piece(int index);
|
|
|
|
|
|
|
|
void close_all_connections();
|
|
|
|
|
|
|
|
piece_picker& picker() { return m_picker; }
|
|
|
|
|
2003-12-01 22:27:27 +01:00
|
|
|
// this is called from the peer_connection
|
|
|
|
// each time a piece has failed the hash
|
|
|
|
// test
|
|
|
|
void piece_failed(int index);
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
// DEBUG
|
|
|
|
#ifndef NDEBUG
|
|
|
|
logger* spawn_logger(const char* title);
|
|
|
|
#endif
|
|
|
|
|
2003-11-20 20:58:29 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
virtual void debug_log(const std::string& line);
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-11-26 15:11:25 +01:00
|
|
|
private:
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
void try_next_tracker();
|
|
|
|
|
|
|
|
enum event_id
|
|
|
|
{
|
|
|
|
event_started = 0,
|
|
|
|
event_stopped,
|
|
|
|
event_completed,
|
|
|
|
event_none
|
|
|
|
};
|
|
|
|
|
|
|
|
// the size of a request block
|
|
|
|
// each piece is divided into these
|
|
|
|
// blocks when requested
|
|
|
|
int m_block_size;
|
|
|
|
|
2003-10-23 18:55:52 +02:00
|
|
|
// is set to true when the torrent has
|
|
|
|
// been aborted.
|
2003-10-23 01:00:57 +02:00
|
|
|
bool m_abort;
|
|
|
|
|
|
|
|
event_id m_event;
|
|
|
|
|
2003-10-23 18:55:52 +02:00
|
|
|
void parse_response(const entry& e, std::vector<peer>& peer_list);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-11-06 11:44:19 +01:00
|
|
|
// TODO: Replace with stat-object
|
|
|
|
// total amount of bytes uploaded, downloaded
|
2003-10-23 01:00:57 +02:00
|
|
|
entry::integer_type m_bytes_uploaded;
|
|
|
|
entry::integer_type m_bytes_downloaded;
|
|
|
|
|
|
|
|
torrent_info m_torrent_file;
|
|
|
|
|
2003-12-07 02:26:57 +01:00
|
|
|
piece_manager m_storage;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
// the time of next tracker request
|
|
|
|
boost::posix_time::ptime m_next_request;
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// DATA FROM TRACKER RESPONSE
|
|
|
|
|
|
|
|
// the number number of seconds between requests
|
|
|
|
// from the tracker
|
|
|
|
int m_duration;
|
|
|
|
|
|
|
|
std::vector<peer_connection*> m_connections;
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
boost::shared_ptr<policy> m_policy;
|
|
|
|
|
|
|
|
detail::session_impl* m_ses;
|
|
|
|
|
|
|
|
piece_picker m_picker;
|
|
|
|
|
|
|
|
// this is an index into m_torrent_file.trackers()
|
|
|
|
int m_last_working_tracker;
|
|
|
|
int m_currently_trying_tracker;
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
// this is a counter that is increased every
|
|
|
|
// second, and when it reaches 10, the policy::pulse()
|
|
|
|
// is called and the time scaler is reset to 0.
|
|
|
|
int m_time_scaler;
|
2003-10-23 01:00:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TORRENT_TORRENT_HPP_INCLUDED
|