From 420ab6bff2204962eaf83887299c772826432d9b Mon Sep 17 00:00:00 2001
From: Arvid Norberg
Date: Sun, 9 Nov 2003 18:17:09 +0000
Subject: [PATCH] *** empty log message ***
---
Jamfile | 9 +-
docs/index.html | 26 ++-
examples/client_test.cpp | 7 +-
include/libtorrent/bencode.hpp | 2 +-
include/libtorrent/debug.hpp | 6 +
include/libtorrent/peer_connection.hpp | 53 +++++-
include/libtorrent/peer_info.hpp | 1 +
include/libtorrent/session.hpp | 19 ++-
project-root.jam | 0
src/entry.cpp | 2 +-
src/peer_connection.cpp | 217 ++++++++++++++++---------
src/piece_picker.cpp | 2 +-
src/session.cpp | 141 ++++++++--------
src/storage.cpp | 2 +-
src/torrent.cpp | 1 +
src/torrent_handle.cpp | 2 +
16 files changed, 310 insertions(+), 180 deletions(-)
create mode 100755 project-root.jam
diff --git a/Jamfile b/Jamfile
index 265207753..eb569a1b8 100755
--- a/Jamfile
+++ b/Jamfile
@@ -1,5 +1,4 @@
-project boost : $(BOOST_ROOT) ;
SOURCES =
entry.cpp
@@ -7,7 +6,6 @@ SOURCES =
piece_picker.cpp
policy.cpp
session.cpp
-# socket_bsd.cpp
socket_win.cpp
stat.cpp
storage.cpp
@@ -20,6 +18,9 @@ SOURCES =
lib torrent
: src/$(SOURCES)
+ zlib//zlib
+ $(BOOST_ROOT)/libs/filesystem/build//boost_filesystem
+ $(BOOST_ROOT)/libs/thread/build//boost_thread
: $(BOOST_ROOT)
$(BOOST_ROOT)
./include
@@ -32,9 +33,7 @@ lib torrent
exe client_test
: examples/client_test.cpp
- torrent
- @boost/libs/filesystem/build/boost_filesystem
- @boost/libs/thread/build/boost_thread
+ torrent
: $(BOOST_ROOT)
$(BOOST_ROOT)
./include
diff --git a/docs/index.html b/docs/index.html
index 7c4576e4a..fb5c2bbbd 100755
--- a/docs/index.html
+++ b/docs/index.html
@@ -56,6 +56,7 @@ The current state includes the following features:
queues torrents for file check, instead of checking all of them in parallel.
uses separate threads for checking files and for main downloader, with a fool-proof
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
+ can limit the upload bandwidth usage
@@ -64,12 +65,12 @@ Functions that are yet to be implemented:
- optimistic unchoke
-
- upload speed cap
- Snubbing
- end game mode
- new allocation model
- fast resume
- file-level piece priority
+
- a good upload speed cap
@@ -159,6 +160,7 @@ class session: public boost::noncopyable
void remove_torrent(const torrent_handle& h);
void set_http_settings(const http_settings& settings);
+ void set_upload_rate_limit(int bytes_per_second);
};
@@ -188,6 +190,20 @@ identify the client. If the string is longer than 7 characters it will
be trimmed down to 7 characters. The default is an empty string.
+
+set_upload_rate_limit() set the maximum number of bytes allowed to be
+sent to peers per second. This bandwidth is distributed among all the peers. If
+you don't want to limit upload rate, you can set this to -1 (the default).
+
+
+
+The destructor of session will notify all trackers that our torrents has been shut down.
+If some trackers are down, they will timout. All this before the destructor of session
+returns. So, it's adviced that any kind of interface (such as windows) are closed before
+destructing the sessoin object. Because it can take a few second for it to finish. The
+timeout can be set with set_http_settings().
+
+
How to parse a torrent file and create a torrent_info object is described below.
@@ -655,6 +671,7 @@ struct peer_info
unsigned int total_upload;
peer_id id;
std::vector<bool> pieces;
+ int upload_limit;
};
@@ -695,6 +712,11 @@ in the torrent. Each boolean tells you if the peer has that piece (if it's set t
or if the peer miss that piece (set to false).
+
+upload_limit is the number of bytes per second we are allowed to send to this
+peer every second. It may be -1 if there's no limit.
+
+
TODO: address
@@ -724,7 +746,7 @@ struct http_settings
tracker_timeout is the number of seconds the tracker connection will
-wait until it considers the tracker to have timed-out. Default value is 30
+wait until it considers the tracker to have timed-out. Default value is 10
seconds.
diff --git a/examples/client_test.cpp b/examples/client_test.cpp
index 91f2dd2b1..728c59ddf 100755
--- a/examples/client_test.cpp
+++ b/examples/client_test.cpp
@@ -44,6 +44,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/http_settings.hpp"
#ifdef WIN32
+
+#if defined(_MSC_VER)
+# define for if (false) {} else for
+#endif
+
#include
#include
@@ -164,7 +169,7 @@ int main(int argc, char* argv[])
{
std::vector handles;
session s(6881, "E\x1");
-
+ s.set_upload_rate_limit(10240);
s.set_http_settings(settings);
for (int i = 0; i < argc-1; ++i)
{
diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp
index a5fa1e298..03b5afb73 100755
--- a/include/libtorrent/bencode.hpp
+++ b/include/libtorrent/bencode.hpp
@@ -68,7 +68,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/entry.hpp"
-#if defined(_MSC_VER) && _MSC_VER < 1300
+#if defined(_MSC_VER)
namespace std
{
using ::isdigit;
diff --git a/include/libtorrent/debug.hpp b/include/libtorrent/debug.hpp
index 382adabfe..eccfa04e5 100755
--- a/include/libtorrent/debug.hpp
+++ b/include/libtorrent/debug.hpp
@@ -77,6 +77,12 @@ namespace libtorrent
virtual ~logger() {}
};
+ struct null_logger: libtorrent::logger
+ {
+ public:
+ virtual void log(const char* text) {}
+ };
+
struct cout_logger: libtorrent::logger
{
public:
diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp
index 98ab2b2a4..f2db0074c 100755
--- a/include/libtorrent/peer_connection.hpp
+++ b/include/libtorrent/peer_connection.hpp
@@ -151,13 +151,36 @@ namespace libtorrent
const stat& statistics() const { return m_statistics; }
// is called once every second by the main loop
- void second_tick() { m_statistics.second_tick(); }
+ void second_tick()
+ {
+ m_statistics.second_tick();
+ m_send_quota_left = m_send_quota;
+ if (m_send_quota > 0) send_buffer_updated();
+ }
boost::shared_ptr get_socket() const { return m_socket; }
const peer_id& get_peer_id() const { return m_peer_id; }
const std::vector& get_bitfield() const { return m_have_piece; }
+ // sets the number of bytes this peer
+ // is allowed to send until it should
+ // stop sending. When it stops sending
+ // it will simply wait for another call
+ // to second_tick() where it will get
+ // more send quota.
+ void set_send_quota(int num_bytes);
+
+ // returns the send quota this peer has
+ // left until will stop sending.
+ // if the send_quota is -1, it means the
+ // quota is unlimited.
+ int send_quota_left() const { return m_send_quota_left; }
+
+ // returns the send quota assigned to this
+ // peer.
+ int send_quota() const { return m_send_quota; }
+
#ifndef NDEBUG
boost::shared_ptr m_logger;
#endif
@@ -176,7 +199,7 @@ namespace libtorrent
enum state
{
read_protocol_length = 0,
- read_protocol_version,
+ read_protocol_string,
read_info_hash,
read_peer_id,
@@ -264,6 +287,20 @@ namespace libtorrent
std::vector m_download_queue;
stat m_statistics;
+
+ // this is used to limit upload bandwidth.
+ // it is reset to the allowed number of
+ // bytes to send frequently. Every time
+ // thie peer send some data,
+ // m_send_quota_left variable will be decreased
+ // so it can limit the number of bytes next
+ // time it sends data. when it reaches zero
+ // the client will stop send data and await
+ // more quota. if it is set to -1, the peer
+ // will ignore the qouta and send at maximum
+ // speed
+ int m_send_quota;
+ int m_send_quota_left;
};
// this is called each time this peer generates some
@@ -271,8 +308,18 @@ namespace libtorrent
// the writibility monitor in the selector.
inline void peer_connection::send_buffer_updated()
{
- if (!has_data()) return;
+ if (!has_data())
+ {
+ if (m_added_to_selector)
+ {
+ m_selector.remove_writable(m_socket);
+ m_added_to_selector = false;
+ }
+ assert(!m_selector.is_writability_monitored(m_socket));
+ return;
+ }
+ assert(has_data());
if (!m_added_to_selector)
{
m_selector.monitor_writability(m_socket);
diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp
index 14233dcec..e5f95b3bc 100755
--- a/include/libtorrent/peer_info.hpp
+++ b/include/libtorrent/peer_info.hpp
@@ -56,6 +56,7 @@ namespace libtorrent
unsigned int total_upload;
peer_id id;
std::vector pieces;
+ int upload_limit;
};
}
diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp
index 4beeb0d42..8a491aac4 100755
--- a/include/libtorrent/session.hpp
+++ b/include/libtorrent/session.hpp
@@ -173,16 +173,18 @@ namespace libtorrent
// the settings for the client
http_settings m_settings;
+ // set to true when the session object
+ // is being destructed and the thread
+ // should exit
volatile bool m_abort;
-
-#ifndef NDEBUG
- boost::shared_ptr create_log(std::string name)
- {
- name = "libtorrent_log_" + name + ".log";
- // current options are file_logger and cout_logger
- return boost::shared_ptr(new file_logger(name.c_str()));
- }
+ // maximum upload rate given in
+ // bytes per second. -1 means
+ // unlimited
+ int m_upload_rate;
+
+#ifndef NDEBUG
+ boost::shared_ptr create_log(std::string name);
boost::shared_ptr m_logger;
#endif
};
@@ -208,6 +210,7 @@ namespace libtorrent
void remove_torrent(const torrent_handle& h);
void set_http_settings(const http_settings& s);
+ void set_upload_rate_limit(int bytes_per_second);
private:
diff --git a/project-root.jam b/project-root.jam
new file mode 100755
index 000000000..e69de29bb
diff --git a/src/entry.cpp b/src/entry.cpp
index afc6fbe04..8b68f63b6 100755
--- a/src/entry.cpp
+++ b/src/entry.cpp
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/entry.hpp"
-#if defined(_MSC_VER) && _MSV_CER < 1300
+#if defined(_MSC_VER)
namespace std
{
using ::isprint;
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index 69495b7e8..3f5da2085 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/session.hpp"
-#if defined(_MSC_VER) && _MSC_VER < 1300
+#if defined(_MSC_VER)
#define for if (false) {} else for
#endif
@@ -94,10 +94,12 @@ libtorrent::peer_connection::peer_connection(
, m_peer_choked(true)
, m_interesting(false)
, m_choked(true)
+ , m_send_quota(-1)
+ , m_send_quota_left(-1)
{
assert(m_torrent != 0);
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
m_logger = m_ses->create_log(s->sender().as_string().c_str());
#endif
@@ -135,9 +137,11 @@ libtorrent::peer_connection::peer_connection(
, m_peer_choked(true)
, m_interesting(false)
, m_choked(true)
+ , m_send_quota(-1)
+ , m_send_quota_left(-1)
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
m_logger = m_ses->create_log(s->sender().as_string().c_str());
#endif
@@ -156,20 +160,57 @@ libtorrent::peer_connection::~peer_connection()
if (m_torrent) m_torrent->remove_peer(this);
}
+void libtorrent::peer_connection::set_send_quota(int num_bytes)
+{
+ assert(num_bytes >= 0);
+ m_send_quota = num_bytes;
+ m_send_quota_left = num_bytes;
+ send_buffer_updated();
+}
+
+
void libtorrent::peer_connection::send_handshake()
{
assert(m_send_buffer.size() == 0);
// add handshake to the send buffer
- m_send_buffer.resize(68);
- const char* version_string = "BitTorrent protocol";
- m_send_buffer[0] = 19;
- std::copy(version_string, version_string+19, m_send_buffer.begin()+1);
- std::fill(m_send_buffer.begin() + 20, m_send_buffer.begin() + 28, 0);
- std::copy(m_torrent->torrent_file().info_hash().begin(), m_torrent->torrent_file().info_hash().end(), m_send_buffer.begin() + 28);
- std::copy(m_ses->get_peer_id().begin(), m_ses->get_peer_id().end(), m_send_buffer.begin() + 48);
+ const char version_string[] = "BitTorrent protocol";
+ const int string_len = sizeof(version_string)-1;
+ int pos = 1;
-#if defined(TORRENT_VERBOSE_LOGGING)
+ m_send_buffer.resize(1 + string_len + 8 + 20 + 20);
+
+ // length of version string
+ m_send_buffer[0] = string_len;
+
+ // version string itself
+ std::copy(
+ version_string
+ , version_string+string_len
+ , m_send_buffer.begin()+pos);
+ pos += string_len;
+
+ // 8 zeroes
+ std::fill(
+ m_send_buffer.begin() + pos
+ , m_send_buffer.begin() + pos + 8
+ , 0);
+ pos += 8;
+
+ // info hash
+ std::copy(
+ m_torrent->torrent_file().info_hash().begin()
+ , m_torrent->torrent_file().info_hash().end()
+ , m_send_buffer.begin() + pos);
+ pos += 20;
+
+ // peer id
+ std::copy(
+ m_ses->get_peer_id().begin()
+ , m_ses->get_peer_id().end()
+ , m_send_buffer.begin() + pos);
+
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> HANDSHAKE\n";
#endif
@@ -187,7 +228,7 @@ bool libtorrent::peer_connection::dispatch_message()
// *************** CHOKE ***************
case msg_choke:
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== CHOKE\n";
#endif
m_peer_choked = true;
@@ -211,7 +252,7 @@ bool libtorrent::peer_connection::dispatch_message()
// *************** UNCHOKE ***************
case msg_unchoke:
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== UNCHOKE\n";
#endif
m_peer_choked = false;
@@ -221,7 +262,7 @@ bool libtorrent::peer_connection::dispatch_message()
// *************** INTERESTED ***************
case msg_interested:
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== INTERESTED\n";
#endif
m_peer_interested = true;
@@ -231,7 +272,7 @@ bool libtorrent::peer_connection::dispatch_message()
// *************** NOT INTERESTED ***************
case msg_not_interested:
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== NOT_INTERESTED\n";
#endif
m_peer_interested = false;
@@ -248,13 +289,13 @@ bool libtorrent::peer_connection::dispatch_message()
if (index >= m_have_piece.size())
return false;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n";
#endif
if (m_have_piece[index])
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " oops.. we already knew that: " << index << "\n";
#endif
}
@@ -276,7 +317,7 @@ bool libtorrent::peer_connection::dispatch_message()
if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8)
return false;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n";
#endif
bool interesting = false;
@@ -298,7 +339,7 @@ bool libtorrent::peer_connection::dispatch_message()
}
if (is_seed)
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " *** THIS IS A SEED ***\n";
#endif
}
@@ -323,7 +364,7 @@ bool libtorrent::peer_connection::dispatch_message()
send_buffer_updated();
}
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
@@ -338,7 +379,7 @@ bool libtorrent::peer_connection::dispatch_message()
std::size_t index = read_int(&m_recv_buffer[1]);
if (index < 0 || index >= m_torrent->torrent_file().num_pieces())
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece index invalid\n";
#endif
return false;
@@ -348,7 +389,7 @@ bool libtorrent::peer_connection::dispatch_message()
if (offset < 0)
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " offset < 0\n";
#endif
return false;
@@ -356,7 +397,7 @@ bool libtorrent::peer_connection::dispatch_message()
if (offset + len > m_torrent->torrent_file().piece_size(index))
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n";
#endif
return false;
@@ -364,7 +405,7 @@ bool libtorrent::peer_connection::dispatch_message()
if (offset % m_torrent->block_size() != 0)
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n";
#endif
return false;
@@ -373,7 +414,7 @@ bool libtorrent::peer_connection::dispatch_message()
piece_block req = m_download_queue.front();
if (req.piece_index != index)
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested index\n";
#endif
return false;
@@ -381,13 +422,13 @@ bool libtorrent::peer_connection::dispatch_message()
if (req.block_index != offset / m_torrent->block_size())
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested offset\n";
#endif
return false;
}
*/
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== PIECE [ piece: " << index << " | s: " << offset << " | l: " << len << " ]\n";
#endif
@@ -479,7 +520,7 @@ bool libtorrent::peer_connection::dispatch_message()
m_selector.remove_writable(m_socket);
}
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== CANCEL [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
break;
@@ -530,7 +571,7 @@ void libtorrent::peer_connection::cancel_block(piece_block block)
// length
write_int(block_size, &m_send_buffer[start_offset]);
start_offset += 4;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#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());
@@ -577,7 +618,7 @@ void libtorrent::peer_connection::request_block(piece_block block)
// length
write_int(block_size, &m_send_buffer[start_offset]);
start_offset += 4;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#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());
@@ -587,7 +628,7 @@ void libtorrent::peer_connection::request_block(piece_block block)
void libtorrent::peer_connection::send_bitfield()
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> BITFIELD\n";
#endif
const int packet_size = (m_have_piece.size() + 7) / 8 + 5;
@@ -610,7 +651,7 @@ void libtorrent::peer_connection::choke()
char msg[] = {0,0,0,1,msg_choke};
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
m_choked = true;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> CHOKE\n";
#endif
send_buffer_updated();
@@ -622,7 +663,7 @@ void libtorrent::peer_connection::unchoke()
char msg[] = {0,0,0,1,msg_unchoke};
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
m_choked = false;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> UNCHOKE\n";
#endif
send_buffer_updated();
@@ -634,7 +675,7 @@ void libtorrent::peer_connection::interested()
char msg[] = {0,0,0,1,msg_interested};
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
m_interesting = true;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> INTERESTED\n";
#endif
send_buffer_updated();
@@ -646,7 +687,7 @@ void libtorrent::peer_connection::not_interested()
char msg[] = {0,0,0,1,msg_not_interested};
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
m_interesting = false;
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> NOT_INTERESTED\n";
#endif
send_buffer_updated();
@@ -657,7 +698,7 @@ void libtorrent::peer_connection::send_have(int index)
char msg[9] = {0,0,0,5,msg_have};
write_int(index, msg+5);
m_send_buffer.insert(m_send_buffer.end(), msg, msg+9);
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> HAVE [ piece: " << index << " ]\n";
#endif
send_buffer_updated();
@@ -681,11 +722,13 @@ void libtorrent::peer_connection::receive_data()
// an error
if (received < 0)
{
- // would block means that no data was ready to be received
+ // would_block means that no data was ready to be received
+ // this should never happen, since we have a selector
+ //assert(m_socket->last_error() != socket::would_block);
if (m_socket->last_error() == socket::would_block) return;
// the connection was closed
- throw network_error(0);
+ throw network_error(m_socket->last_error());
}
if (received > 0)
@@ -701,28 +744,25 @@ void libtorrent::peer_connection::receive_data()
{
case read_protocol_length:
m_packet_size = reinterpret_cast(m_recv_buffer[0]);
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " protocol length: " << m_packet_size << "\n";
#endif
- m_state = read_protocol_version;
- if (m_packet_size != 19)
- throw network_error(0);
+ m_state = read_protocol_string;
m_recv_buffer.resize(m_packet_size);
m_recv_pos = 0;
break;
- case read_protocol_version:
+ case read_protocol_string:
{
- const char* protocol_version = "BitTorrent protocol";
- #if defined(TORRENT_VERBOSE_LOGGING)
- (*m_logger) << m_socket->sender().as_string() << " protocol name: " << std::string(m_recv_buffer.begin(), m_recv_buffer.end()) << "\n";
+ #ifndef NDEBUG
+ (*m_logger) << m_socket->sender().as_string() << " protocol: '" << std::string(m_recv_buffer.begin(), m_recv_buffer.end()) << "'\n";
#endif
- if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), protocol_version))
- {
- // unknown protocol, close connection
+ const char protocol_string[] = "BitTorrent protocol";
+ const int protocol_len = sizeof(protocol_string) - 1;
+ if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), protocol_string))
throw network_error(0);
- }
+
m_state = read_info_hash;
m_packet_size = 28;
m_recv_pos = 0;
@@ -738,7 +778,11 @@ void libtorrent::peer_connection::receive_data()
if (m_torrent == 0)
{
- // no, we have to see if there's a torrent with the
+ // TODO: if the protocol is to be extended
+ // these 8 bytes would be used to describe the
+ // extensions available on the other side
+
+ // now, we have to see if there's a torrent with the
// info_hash we got from the peer
sha1_hash info_hash;
std::copy(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (char*)info_hash.begin());
@@ -747,7 +791,7 @@ void libtorrent::peer_connection::receive_data()
if (m_torrent == 0)
{
// we couldn't find the torrent!
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " couldn't find a torrent with the given info_hash\n";
#endif
throw network_error(0);
@@ -769,7 +813,7 @@ void libtorrent::peer_connection::receive_data()
// verify info hash
if (!std::equal(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (const char*)m_torrent->torrent_file().info_hash().begin()))
{
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " received invalid info_hash\n";
#endif
throw network_error(0);
@@ -780,7 +824,7 @@ void libtorrent::peer_connection::receive_data()
m_packet_size = 20;
m_recv_pos = 0;
m_recv_buffer.resize(20);
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " info_hash received\n";
#endif
break;
@@ -796,7 +840,7 @@ void libtorrent::peer_connection::receive_data()
// can this be correct?
if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (const char*)m_peer_id.begin()))
{
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " invalid peer_id (it doesn't equal the one from the tracker)\n";
#endif
throw network_error(0);
@@ -809,7 +853,7 @@ void libtorrent::peer_connection::receive_data()
std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)m_peer_id.begin());
if (m_torrent->num_connections(m_peer_id) > 1)
{
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " duplicate connection, closing\n";
#endif
throw network_error(0);
@@ -820,7 +864,7 @@ void libtorrent::peer_connection::receive_data()
m_packet_size = 4;
m_recv_pos = 0;
m_recv_buffer.resize(4);
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " received peer_id\n";
#endif
break;
@@ -833,7 +877,7 @@ void libtorrent::peer_connection::receive_data()
// don't accept packets larger than 1 MB
if (m_packet_size > 1024*1024 || m_packet_size < 0)
{
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " packet too large (packet_size > 1 Megabyte), abort\n";
#endif
// packet too large
@@ -857,7 +901,7 @@ void libtorrent::peer_connection::receive_data()
case read_packet:
if (!dispatch_message())
{
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " received invalid packet\n";
#endif
// invalid message
@@ -880,7 +924,10 @@ bool libtorrent::peer_connection::has_data() const throw()
{
// if we have requests or pending data to be sent or announcements to be made
// we want to send data
- return (!m_requests.empty() && !m_choked) || !m_send_buffer.empty() || !m_announce_queue.empty();
+ return ((!m_requests.empty() && !m_choked)
+ || !m_send_buffer.empty()
+ || !m_announce_queue.empty())
+ && m_send_quota_left != 0;
}
// --------------------------
@@ -913,18 +960,19 @@ void libtorrent::peer_connection::send_data()
throw network_error(0);
}
- if (m_sending_piece.index() != r.piece)
- {
- m_sending_piece.open(
- m_torrent->filesystem()
- , r.piece
- , piece_file::in
- , r.start);
+ m_sending_piece.open(
+ m_torrent->filesystem()
+ , r.piece
+ , piece_file::in
+ , r.start);
#ifndef NDEBUG
- assert(m_torrent->filesystem()->verify_piece(m_sending_piece) && "internal error");
- m_sending_piece.open(m_torrent->filesystem(), r.piece, piece_file::in);
+ assert(m_torrent->filesystem()->verify_piece(m_sending_piece) && "internal error");
+ m_sending_piece.open(
+ m_torrent->filesystem()
+ , r.piece
+ , piece_file::in
+ , r.start);
#endif
- }
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);
@@ -936,7 +984,7 @@ void libtorrent::peer_connection::send_data()
assert(r.start == m_sending_piece.tell());
m_sending_piece.read(&m_send_buffer[send_buffer_offset+13], r.length);
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
// let the torrent keep track of how much we have uploaded
@@ -944,7 +992,7 @@ void libtorrent::peer_connection::send_data()
}
else
{
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string()
<< " *** WARNING [ illegal piece request idx: " << r.piece
<< " | s: " << r.start
@@ -970,22 +1018,33 @@ void libtorrent::peer_connection::send_data()
m_announce_queue.clear();
}
+ assert(m_send_quota_left != 0);
+
// send the actual buffer
if (!m_send_buffer.empty())
{
+ int amount_to_send = m_send_buffer.size();
+ assert(m_send_quota_left != 0);
+ if (m_send_quota_left > 0)
+ amount_to_send = std::min(m_send_quota_left, amount_to_send);
// we have data that's scheduled for sending
int sent = m_socket->send(
&m_send_buffer[0]
- , m_send_buffer.size());
+ , amount_to_send);
- #if defined(TORRENT_VERBOSE_LOGGING)
+ #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> SENT [ length: " << sent << " ]\n";
#endif
if (sent > 0)
{
m_statistics.sent_bytes(sent);
+ if (m_send_quota_left != -1)
+ {
+ assert(m_send_quota_left >= sent);
+ m_send_quota_left -= sent;
+ }
// empty the entire buffer at once or if
// only a part of the buffer could be sent
@@ -1011,13 +1070,9 @@ void libtorrent::peer_connection::send_data()
}
assert(m_added_to_selector);
- if (!has_data())
- {
- m_selector.remove_writable(m_socket);
- m_added_to_selector = false;
- }
+ send_buffer_updated();
#ifndef NDEBUG
- else
+ if (has_data())
{
if (m_socket->is_writable())
{
@@ -1037,7 +1092,7 @@ void libtorrent::peer_connection::keep_alive()
char noop[] = {0,0,0,0};
m_send_buffer.insert(m_send_buffer.end(), noop, noop+4);
m_last_sent = boost::posix_time::second_clock::local_time();
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " ==> NOP\n";
#endif
send_buffer_updated();
diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp
index f19c7da81..cdcd38d00 100755
--- a/src/piece_picker.cpp
+++ b/src/piece_picker.cpp
@@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_connection.hpp"
#endif
-#if defined(_MSC_VER) && _MSC_VER < 1300
+#if defined(_MSC_VER)
#define for if (false) {} else for
#endif
diff --git a/src/session.cpp b/src/session.cpp
index 0c6d8ab1c..4d6831aa9 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -59,20 +59,6 @@ namespace std
};
#endif
-/*
-
-DESIGN OVERVIEW AND RATIONALE
-
-The main goal of this library is to be efficient, primarily memory-wise
-but also CPU-wise. This goal has a number of implications:
-
-* It must handle multiple torrents (multiple processes uses much more memory)
-* It relies on a well working disk chache, since it will download directly to disk. This is
- to scale better when having many peer connections.
-*
-
-*/
-
namespace libtorrent
{
namespace detail
@@ -149,6 +135,7 @@ namespace libtorrent
: m_abort(false)
, m_tracker_manager(m_settings)
, m_listen_port(listen_port)
+ , m_upload_rate(-1)
{
// ---- generate a peer id ----
@@ -178,11 +165,9 @@ namespace libtorrent
void session_impl::operator()()
{
eh_initializer();
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
m_logger = create_log("main session");
#endif
- try
- {
boost::shared_ptr listener(new socket(socket::tcp, false));
int max_port = m_listen_port + 9;
@@ -206,7 +191,7 @@ namespace libtorrent
break;
}
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << "listening on port: " << m_listen_port << "\n";
#endif
m_selector.monitor_readability(listener);
@@ -233,6 +218,17 @@ namespace libtorrent
for(;;)
{
+
+#ifndef NDEBUG
+ for (connection_map::iterator i = m_connections.begin();
+ i != m_connections.end();
+ ++i)
+ {
+ assert(i->second->has_data() == m_selector.is_writability_monitored(i->first));
+ }
+#endif
+
+
// if nothing happens within 500000 microseconds (0.5 seconds)
// do the loop anyway to check if anything else has changed
// (*m_logger) << "sleeping\n";
@@ -264,9 +260,6 @@ namespace libtorrent
// RECEIVE SOCKETS
// ************************
- // TODO: once every second or so, all sockets should receive_data() to purge connections
- // that has been closed. Otherwise we have to wait 2 minutes for their timeout
-
// let the readable clients receive data
for (std::vector >::iterator i = readable_clients.begin();
i != readable_clients.end();
@@ -280,14 +273,16 @@ namespace libtorrent
if (s)
{
// we got a connection request!
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << s->sender().as_string() << " <== INCOMING CONNECTION\n";
#endif
// TODO: the send buffer size should be controllable from the outside
// s->set_send_bufsize(2048);
// TODO: add some possibility to filter IP:s
- boost::shared_ptr c(new peer_connection(this, m_selector, s));
+ boost::shared_ptr c(
+ new peer_connection(this, m_selector, s));
+ if (m_upload_rate != -1) c->set_send_quota(100);
m_connections.insert(std::make_pair(s, c));
m_selector.monitor_readability(s);
m_selector.monitor_errors(s);
@@ -378,51 +373,10 @@ namespace libtorrent
++i)
{
assert(i->second->has_data() == m_selector.is_writability_monitored(i->first));
-// if (m_selector.is_writability_monitored(i->first))
-// assert(i->second->has_data());
}
#endif
- // clear all writablility monitors and add
- // the ones who still has data to send
-/* m_selector.clear_writable();
-
-
- // ************************
- // BUILD WRITER LIST
- // ************************
-
- // TODO: REWRITE THIS! DON'T GO THROUGH THIS LOOP EVERY TIME!
-
- // loop over all clients and purge the ones that has timed out
- // and check if they have pending data to be sent
- for (connection_map::iterator i = m_connections.begin();
- i != m_connections.end();)
- {
- connection_map::iterator j = i;
- ++i;
- if (j->second->has_timed_out())
- {
- m_selector.remove(j->first);
- m_connections.erase(j);
- }
- else
- {
- j->second->keep_alive();
- if (j->second->has_data())
- {
- // (*m_logger) << j->first->sender().as_string() << " has data\n";
- m_selector.monitor_writability(j->first);
- }
- else
- {
- // (*m_logger) << j->first->sender().as_string() << " has NO data\n";
- }
- }
- }
-*/
- // (*m_logger) << "time: " << std::clock()-timer << "\n";
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
if (d.seconds() < 1) continue;
timer = boost::posix_time::second_clock::local_time();
@@ -432,6 +386,23 @@ namespace libtorrent
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
// ************************
+ // distribute the maximum upload rate among the peers
+ // TODO: implement an intelligent algorithm that
+ // will shift bandwidth from the peers that can't
+ // utilize all their assigned bandwidth to the peers
+ // that actually can maintain the upload rate.
+ if (m_upload_rate != -1 && !m_connections.empty())
+ {
+ assert(m_upload_rate >= 0);
+ int share = m_upload_rate / m_connections.size();
+ for (connection_map::iterator i = m_connections.begin();
+ i != m_connections.end();
+ ++i)
+ {
+ i->second->set_send_quota(share);
+ }
+ }
+
// do the second_tick() on each connection
// this will update their statistics (download and upload speeds)
// also purge sockets that have timed out
@@ -481,7 +452,7 @@ namespace libtorrent
}
m_tracker_manager.tick();
-#if defined(TORRENT_VERBOSE_LOGGING)
+#ifndef NDEBUG
(*m_logger) << "peers: " << m_connections.size() << " \n";
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();
@@ -503,17 +474,6 @@ namespace libtorrent
t.nsec += 1000000;
boost::thread::sleep(t);
}
- }
- catch(const std::exception& e)
- {
- std::cerr << e.what() << "\n";
- }
- catch(...)
- {
- std::cerr << "error\n";
- }
-
-
}
@@ -527,6 +487,19 @@ namespace libtorrent
return 0;
}
+#ifndef NDEBUG
+ boost::shared_ptr session_impl::create_log(std::string name)
+ {
+ name = "libtorrent_log_" + name + ".log";
+ // current options are file_logger and cout_logger
+#if defined(TORRENT_VERBOSE_LOGGING)
+ return boost::shared_ptr(new file_logger(name.c_str()));
+#else
+ return boost::shared_ptr(new null_logger());
+#endif
+ }
+#endif
+
}
session::session(int listen_port, const std::string& fingerprint)
@@ -627,6 +600,22 @@ namespace libtorrent
m_checker_thread.join();
}
+ void session::set_upload_rate_limit(int bytes_per_second)
+ {
+ assert(bytes_per_second > 0);
+ boost::mutex::scoped_lock l(m_impl.m_mutex);
+ m_impl.m_upload_rate = bytes_per_second;
+ if (m_impl.m_upload_rate != -1 || !m_impl.m_connections.empty())
+ return;
+
+ for (detail::session_impl::connection_map::iterator i
+ = m_impl.m_connections.begin();
+ i != m_impl.m_connections.end();)
+ {
+ i->second->set_send_quota(-1);
+ }
+ }
+
// TODO: document
// TODO: if the first 4 charachters are printable
// maybe they should be considered a fingerprint?
diff --git a/src/storage.cpp b/src/storage.cpp
index 654e19483..b790a2623 100755
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -48,7 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/hasher.hpp"
#include "libtorrent/session.hpp"
-#if defined(_MSC_VER) && _MSV_CER < 1300
+#if defined(_MSC_VER)
#define for if (false) {} else for
#endif
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 831dbd1ec..a11290477 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -347,6 +347,7 @@ namespace libtorrent
, this
, s
, id));
+ if (m_ses->m_upload_rate != -1) c->set_send_quota(100);
detail::session_impl::connection_map::iterator p =
m_ses->m_connections.insert(std::make_pair(s, c)).first;
attach_peer(boost::get_pointer(p->second));
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 8779dc87e..6280b393e 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -139,6 +139,8 @@ namespace libtorrent
p.total_download = statistics.total_download();
p.total_upload = statistics.total_upload();
+ p.upload_limit = peer->send_quota();
+
p.flags = 0;
if (peer->is_interesting()) p.flags |= peer_info::interesting;
if (peer->has_choked()) p.flags |= peer_info::choked;