1
0
mirror of https://github.com/asamy/ctorrent synced 2025-10-05 23:52:41 +02:00

fix bitset::count() bug and improvements

Signed-off-by: Ahmed Samy <f.fallen45@gmail.com>
This commit is contained in:
Ahmed Samy
2016-08-21 20:58:00 +00:00
parent 91b4835a1b
commit 77f56ed6f6
13 changed files with 134 additions and 97 deletions

View File

@@ -13,9 +13,9 @@ DEP_DIR = dep
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d DEPFLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d
CXX = $(CROSS_BUILD)g++ CXX = $(CROSS_BUILD)g++
BTYPE = -O3 BTYPE = -O0 -g
CXXFLAGS = -std=c++0x $(DEPFLAGS) $(BTYPE) -fopenmp \ CXXFLAGS = -std=c++0x $(DEPFLAGS) $(BTYPE) -fopenmp \
-Wall -Wextra -Wno-sign-compare -Wno-unused-variable -Wno-unused-parameter -I"." -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-parameter -I"."
LIBS += -fopenmp -lboost_system -lboost_filesystem -lboost_program_options LIBS += -fopenmp -lboost_system -lboost_filesystem -lboost_program_options
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)

View File

@@ -99,7 +99,7 @@ VectorType Bencode::readVector()
return ret; return ret;
switch (byte) { switch (byte) {
case 'i': ret.push_back(readInt()); break; case 'i': ret.push_back(readUint()); break;
case 'l': ret.push_back(readVector()); break; case 'l': ret.push_back(readVector()); break;
case 'd': ret.push_back(readDictionary()); break; case 'd': ret.push_back(readDictionary()); break;
case 'e': return ret; case 'e': return ret;
@@ -143,7 +143,7 @@ Dictionary Bencode::readDictionary()
return Dictionary(); return Dictionary();
switch (byte) { switch (byte) {
case 'i': ret[key] = readInt(); break; case 'i': ret[key] = readUint(); break;
case 'l': ret[key] = readVector(); break; case 'l': ret[key] = readVector(); break;
case 'd': ret[key] = readDictionary(); break; case 'd': ret[key] = readDictionary(); break;
default: default:

View File

@@ -97,7 +97,7 @@ void Peer::verify()
m_peerId = peerId; m_peerId = peerId;
m_conn->write(m_handshake, 68); m_conn->write(m_handshake, 68);
m_torrent->handleNewPeer(shared_from_this()); m_torrent->handleNewPeer(shared_from_this());
m_eventId = g_sched.addEvent(std::bind(&Peer::sendKeepAlive, shared_from_this()), KEEPALIVE_INTERVAL); // m_eventId = g_sched.addEvent(std::bind(&Peer::sendKeepAlive, shared_from_this()), KEEPALIVE_INTERVAL);
m_conn->read(4, std::bind(&Peer::handle, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); m_conn->read(4, std::bind(&Peer::handle, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}); });
} }
@@ -226,7 +226,7 @@ void Peer::handleMessage(MessageType messageType, InputMessage in)
return handleError("received too big piece block of size " + bytesToHumanReadable(payloadSize, true)); return handleError("received too big piece block of size " + bytesToHumanReadable(payloadSize, true));
auto it = std::find_if(m_queue.begin(), m_queue.end(), auto it = std::find_if(m_queue.begin(), m_queue.end(),
[index](const Piece *piece) { return piece->index == index; }); [index](const Piece *piece) { return piece->index == index; });
if (it == m_queue.end()) if (it == m_queue.end())
return handleError("received piece " + std::to_string(index) + " which we did not ask for"); return handleError("received piece " + std::to_string(index) + " which we did not ask for");
@@ -240,17 +240,11 @@ void Peer::handleMessage(MessageType messageType, InputMessage in)
m_queue.erase(it); m_queue.erase(it);
delete piece; delete piece;
} else { } else {
PieceBlock *block = &piece->blocks[blockIndex];
uint8_t *payload = in.getBuffer(payloadSize); uint8_t *payload = in.getBuffer(payloadSize);
if (block->rpos != 0) { PieceBlock *block = &piece->blocks[blockIndex];
memcpy(block->data, payload, std::max(payloadSize, block->size - block->rpos)); block->size = payloadSize;
free(payload); block->data = payload;
block->rpos += payloadSize; ++piece->currentBlocks;
} else {
block->size = block->rpos = payloadSize;
block->data = payload;
++piece->currentBlocks;
}
if (piece->currentBlocks == piece->numBlocks) { if (piece->currentBlocks == piece->numBlocks) {
DataBuffer<uint8_t> pieceData; DataBuffer<uint8_t> pieceData;
@@ -311,7 +305,7 @@ void Peer::handlePieceBlockData(size_t index, size_t begin, const uint8_t *block
{ {
// Check if piece block cancel was issued // Check if piece block cancel was issued
auto it = std::find_if(m_requestedBlocks.begin(), m_requestedBlocks.end(), auto it = std::find_if(m_requestedBlocks.begin(), m_requestedBlocks.end(),
[=] (const PieceBlockInfo &i) { return i.index == index && i.begin == begin; } ); [=] (const PieceBlockInfo &i) { return i.index == index && i.begin == begin; } );
if (it == m_requestedBlocks.end()) if (it == m_requestedBlocks.end())
return; return;

View File

@@ -66,11 +66,7 @@ public:
void connect(const std::string &ip, const std::string &port); void connect(const std::string &ip, const std::string &port);
protected: protected:
// Process piece blocks requested, send keepalive, etc.
void process();
// Used only in server verification (e.g. peer connected to us)
void verify(); void verify();
void handle(const uint8_t *data, size_t size); void handle(const uint8_t *data, size_t size);
void handleMessage(MessageType mType, InputMessage in); void handleMessage(MessageType mType, InputMessage in);
void handleError(const std::string &errmsg); void handleError(const std::string &errmsg);
@@ -100,10 +96,9 @@ protected:
private: private:
struct PieceBlock { struct PieceBlock {
size_t size; size_t size;
size_t rpos;
uint8_t *data; uint8_t *data;
PieceBlock() { data = nullptr; size = rpos = 0; } PieceBlock() { data = nullptr; size = 0; }
~PieceBlock() { delete []data; } ~PieceBlock() { delete []data; }
}; };

View File

@@ -30,6 +30,9 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <random> #include <random>
#include <fstream>
extern std::ofstream logfile;
Torrent::Torrent() Torrent::Torrent()
: m_listener(nullptr), : m_listener(nullptr),
@@ -159,12 +162,10 @@ bool Torrent::checkTrackers()
bool Torrent::nextConnection() bool Torrent::nextConnection()
{ {
if (m_listener) { if (m_listener) {
m_listener->accept( m_listener->accept([this] (const ConnectionPtr &c) {
[this] (const ConnectionPtr &c) { auto peer = std::make_shared<Peer>(c, this);
auto peer = std::make_shared<Peer>(c, this); peer->verify();
peer->verify(); });
}
);
return true; return true;
} }
@@ -175,7 +176,7 @@ bool Torrent::nextConnection()
bool Torrent::queryTrackers(const TrackerQuery &query, uint16_t port) bool Torrent::queryTrackers(const TrackerQuery &query, uint16_t port)
{ {
bool success = queryTracker(m_meta.tracker(), query, port); bool success = queryTracker(m_meta.tracker(), query, port);
if (m_meta.trackers().empty()) if (success)
return success; return success;
for (const boost::any &s : m_meta.trackers()) { for (const boost::any &s : m_meta.trackers()) {
@@ -186,10 +187,10 @@ bool Torrent::queryTrackers(const TrackerQuery &query, uint16_t port)
return true; return true;
} else if (s.type() == typeid(std::string) && } else if (s.type() == typeid(std::string) &&
queryTracker(Bencode::cast<std::string>(&s), query, port)) queryTracker(Bencode::cast<std::string>(&s), query, port))
return true; return true;
} }
return success; return false;
} }
bool Torrent::queryTracker(const std::string &furl, const TrackerQuery &q, uint16_t tport) bool Torrent::queryTracker(const std::string &furl, const TrackerQuery &q, uint16_t tport)
@@ -293,6 +294,7 @@ void Torrent::addPeer(const PeerPtr &peer)
if (it != m_blacklisted.end()) if (it != m_blacklisted.end())
m_blacklisted.erase(it); m_blacklisted.erase(it);
logfile << peer->getIP() << ": now connected" << std::endl;
m_peers.insert(std::make_pair(peer->ip(), peer)); m_peers.insert(std::make_pair(peer->ip(), peer));
} }
@@ -301,6 +303,8 @@ void Torrent::removePeer(const PeerPtr &peer, const std::string &errmsg)
auto it = m_peers.find(peer->ip()); auto it = m_peers.find(peer->ip());
if (it != m_peers.end()) if (it != m_peers.end())
m_peers.erase(it); m_peers.erase(it);
logfile << peer->getIP() << ": closing: " << errmsg << std::endl;
} }
void Torrent::disconnectPeers() void Torrent::disconnectPeers()
@@ -325,51 +329,58 @@ void Torrent::sendBitfield(const PeerPtr &peer)
void Torrent::requestPiece(const PeerPtr &peer) void Torrent::requestPiece(const PeerPtr &peer)
{ {
size_t index = m_fileManager.getPieceforRequest([peer] (size_t i) { return peer->hasPiece(i); }); size_t index = m_fileManager.getPieceforRequest(std::bind(&Peer::hasPiece, peer, std::placeholders::_1));
if (index != std::numeric_limits<size_t>::max()) if (index != std::numeric_limits<size_t>::max())
peer->sendPieceRequest(index); peer->sendPieceRequest(index);
} }
bool Torrent::handlePieceCompleted(const PeerPtr &peer, uint32_t index, DataBuffer<uint8_t> &&data) bool Torrent::handlePieceCompleted(const PeerPtr &peer, uint32_t index, DataBuffer<uint8_t> &&data)
{ {
uint32_t downloaded = data.size(); logfile << peer->getIP() << ": finished downloading piece: " << index << std::endl;
if (m_fileManager.writePieceBlock(index, peer->ip(), std::move(data))) { if (m_fileManager.writePieceBlock(index, peer->ip(), std::move(data)))
m_downloadedBytes += downloaded;
return true; return true;
}
m_wastedBytes += downloaded; m_wastedBytes += data.size();
++m_hashMisses; ++m_hashMisses;
return false; return false;
} }
bool Torrent::handleRequestBlock(const PeerPtr &peer, uint32_t index, uint32_t begin, uint32_t length) bool Torrent::handleRequestBlock(const PeerPtr &peer, uint32_t index, uint32_t begin, uint32_t length)
{ {
logfile << peer->getIP() << ": Requested piece block: " << index << std::endl;
return m_fileManager.requestPieceBlock(index, peer->ip(), begin, length); return m_fileManager.requestPieceBlock(index, peer->ip(), begin, length);
} }
void Torrent::onPieceWriteComplete(uint32_t from, uint32_t index) void Torrent::onPieceWriteComplete(uint32_t from, size_t index)
{ {
logfile << ip2str(from) << ": Finished writing piece: " << index << std::endl;
logfile << "Pieces so far: " << m_fileManager.completedPieces() << "/" << m_fileManager.totalPieces() << std::endl;
m_downloadedBytes += m_fileManager.pieceSize(index);
for (const auto &it : m_peers) for (const auto &it : m_peers)
if (!it.second->hasPiece(index)) if (it.second->ip() != from && !it.second->hasPiece(index))
it.second->sendHave(index); it.second->sendHave(index);
} }
void Torrent::onPieceReadComplete(uint32_t from, uint32_t index, uint32_t begin, uint8_t *block, size_t size) void Torrent::onPieceReadComplete(uint32_t from, size_t index, int64_t begin, uint8_t *block, size_t size)
{ {
auto it = m_peers.find(from); auto it = m_peers.find(from);
if (it != m_peers.end()) { if (it != m_peers.end()) {
it->second->sendPieceBlock(index, begin, block, size); it->second->sendPieceBlock(index, begin, block, size);
m_uploadedBytes += size; m_uploadedBytes += size;
} }
delete []block;
} }
void Torrent::handleTrackerError(Tracker *tracker, const std::string &error) void Torrent::handleTrackerError(Tracker *tracker, const std::string &error)
{ {
logfile << tracker->host() << ": (T): " << error << std::endl;
} }
void Torrent::handlePeerDebug(const PeerPtr &peer, const std::string &msg) void Torrent::handlePeerDebug(const PeerPtr &peer, const std::string &msg)
{ {
logfile << peer->getIP() << ": " << msg << std::endl;
} }
void Torrent::handleNewPeer(const PeerPtr &peer) void Torrent::handleNewPeer(const PeerPtr &peer)

View File

@@ -76,10 +76,10 @@ public:
clock_t elapsed(); clock_t elapsed();
// Get associated meta info for this torrent // Get associated meta info for this torrent
const TorrentMeta *meta() const { return &m_meta; } TorrentMeta *meta() { return &m_meta; }
// Get associated file manager for this torrent // Get associated file manager for this torrent
const TorrentFileManager *fileManager() const { return &m_fileManager; } TorrentFileManager *fileManager() { return &m_fileManager; }
protected: protected:
bool queryTrackers(const TrackerQuery &r, uint16_t port); bool queryTrackers(const TrackerQuery &r, uint16_t port);
@@ -108,8 +108,8 @@ protected:
public: public:
// TorrentFileManager -> Torrent // TorrentFileManager -> Torrent
void onPieceWriteComplete(uint32_t from, uint32_t index); void onPieceWriteComplete(uint32_t from, size_t index);
void onPieceReadComplete(uint32_t from, uint32_t index, uint32_t begin, uint8_t *block, size_t size); void onPieceReadComplete(uint32_t from, size_t index, int64_t begin, uint8_t *block, size_t size);
private: private:
Server *m_listener; Server *m_listener;

View File

@@ -44,8 +44,8 @@ struct ReadRequest {
size_t index; size_t index;
uint32_t id; uint32_t id;
uint32_t from; uint32_t from;
int64_t begin; size_t begin;
int64_t size; size_t size;
}; };
struct LeastReadRequest { struct LeastReadRequest {
bool operator() (const ReadRequest &lhs, const ReadRequest &rhs) const { bool operator() (const ReadRequest &lhs, const ReadRequest &rhs) const {
@@ -89,21 +89,26 @@ public:
void unlock_and_notify() { m_mutex.unlock(); m_condition.notify_all(); } void unlock_and_notify() { m_mutex.unlock(); m_condition.notify_all(); }
void push_read(const ReadRequest &r) { m_readRequests.push(r); } void push_read(const ReadRequest &r) { m_readRequests.push(r); }
void push_write(WriteRequest &&w) { m_writeRequests.push(std::move(w)); } void push_write(WriteRequest &&w) { m_writeRequests.push(std::move(w)); m_pendingBits.set(w.index); }
void push_file(const TorrentFile &f) { m_files.push_back(f); } void push_file(const TorrentFile &f) { m_files.push_back(f); }
void scan_file(const TorrentFile &f); void scan_file(const TorrentFile &f);
void scan_pieces(); void scan_pieces();
const bitset *completed_bits() const { return &m_completedBits; } const bitset *completed_bits() const { return &m_completedBits; }
size_t pending() const { return m_pendingBits.count(); }
size_t completed_pieces() const { return m_completedBits.count(); } size_t completed_pieces() const { return m_completedBits.count(); }
size_t total_pieces() const { return m_pieces.size(); } size_t total_pieces() const { return m_pieces.size(); }
size_t get_next_piece(const std::function<bool (size_t)> &fun); size_t get_next_piece(const std::function<bool (size_t)> &fun);
size_t compute_downloaded(); size_t compute_downloaded();
bool piece_done(size_t index) const { return index < m_pieces.size() && m_completedBits.test(index); } bool piece_done(size_t index) const { return index < m_pieces.size() && m_completedBits.test(index); }
bool piece_pending(size_t index) const { return index < m_pieces.size() && m_pendingBits.test(index); }
bool intact(size_t index) const { return index < m_pieces.size(); } bool intact(size_t index) const { return index < m_pieces.size(); }
bool is_read_eligible(size_t index, int64_t end) const { return m_completedBits.test(index) && end < piece_length(index); } bool is_read_eligible(size_t index, int64_t end) const { return m_completedBits.test(index) && end < piece_length(index); }
bool is_write_eligible(size_t index, const uint8_t *data, size_t size) const { bool is_write_eligible(size_t index, const uint8_t *data, size_t size) const {
if (m_pendingBits.test(index))
return false;
boost::uuids::detail::sha1 sha1; boost::uuids::detail::sha1 sha1;
sha1.process_bytes(data, size); sha1.process_bytes(data, size);
@@ -133,6 +138,7 @@ public:
auto sha1sums = m_torrent->meta()->sha1sums(); auto sha1sums = m_torrent->meta()->sha1sums();
m_pieces.reserve(sha1sums.size()); m_pieces.reserve(sha1sums.size());
m_completedBits.construct(sha1sums.size()); m_completedBits.construct(sha1sums.size());
m_pendingBits.construct(sha1sums.size());
for (sha1sum s : sha1sums) for (sha1sum s : sha1sums)
m_pieces.push_back(Piece(s)); m_pieces.push_back(Piece(s));
@@ -149,6 +155,8 @@ private:
std::queue<WriteRequest> m_writeRequests; std::queue<WriteRequest> m_writeRequests;
bitset m_completedBits; bitset m_completedBits;
bitset m_pendingBits;
std::vector<TorrentFile> m_files; std::vector<TorrentFile> m_files;
std::vector<Piece> m_pieces; std::vector<Piece> m_pieces;
@@ -165,11 +173,11 @@ void TorrentFileManagerImpl::scan_file(const TorrentFile &f)
{ {
FILE *fp = f.fp; FILE *fp = f.fp;
fseek(fp, 0L, SEEK_END); fseek(fp, 0L, SEEK_END);
off64_t fileLength = ftello64(fp); size_t fileLength = ftello64(fp);
fseek(fp, 0L, SEEK_SET); fseek(fp, 0L, SEEK_SET);
if (f.info.length > fileLength) { if (f.info.length > fileLength) {
// truncate(f.info.path.c_str(), f.info.length); truncate(f.info.path.c_str(), f.info.length);
return; return;
} }
@@ -267,14 +275,18 @@ void TorrentFileManagerImpl::thread()
// mark the piece as fully have before we fully wrote it to disk. // mark the piece as fully have before we fully wrote it to disk.
while (!m_writeRequests.empty() && !m_stopped) { while (!m_writeRequests.empty() && !m_stopped) {
const WriteRequest &w = m_writeRequests.front(); const WriteRequest &w = m_writeRequests.front();
if (process_write(w)) if (!process_write(w))
m_writeRequests.pop(); break;
m_writeRequests.pop();
} }
while (!m_readRequests.empty() && !m_stopped) { while (!m_readRequests.empty() && !m_stopped) {
ReadRequest r = m_readRequests.top(); ReadRequest r = m_readRequests.top();
if (process_read(r)) if (!process_read(r))
m_readRequests.pop(); break;
m_readRequests.pop();
} }
lock.unlock(); lock.unlock();
@@ -286,16 +298,16 @@ bool TorrentFileManagerImpl::process_read(const ReadRequest &r)
const TorrentMeta *meta = m_torrent->meta(); const TorrentMeta *meta = m_torrent->meta();
int64_t blockBegin = r.begin + r.index * meta->pieceLength(); int64_t blockBegin = r.begin + r.index * meta->pieceLength();
int64_t blockEnd = r.begin + r.size; int64_t blockEnd = r.begin + r.size;
uint8_t block[r.size]; uint8_t *block = new uint8_t[r.size];
int64_t writePos = 0; size_t writePos = 0;
for (const TorrentFile &f : m_files) { for (const TorrentFile &f : m_files) {
int64_t filePos = blockBegin + writePos;
const TorrentFileInfo &i = f.info; const TorrentFileInfo &i = f.info;
size_t filePos = blockBegin + writePos;
if (filePos < i.begin) if (filePos < i.begin)
return false; return false;
int64_t fileEnd = i.begin + i.length; size_t fileEnd = i.begin + i.length;
if (filePos > fileEnd) if (filePos > fileEnd)
continue; continue;
fseek(f.fp, filePos - i.begin, SEEK_SET); fseek(f.fp, filePos - i.begin, SEEK_SET);
@@ -311,15 +323,14 @@ bool TorrentFileManagerImpl::process_read(const ReadRequest &r)
} }
} }
// TODO: schedule this as well, make sure "block" will live for the period g_sched.addEvent(std::bind(&Torrent::onPieceReadComplete, m_torrent, r.from, r.index, r.begin, block, r.size), 0);
m_torrent->onPieceReadComplete(r.from, r.index, r.begin, block, r.size);
return true; return true;
} }
bool TorrentFileManagerImpl::process_write(const WriteRequest &w) bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
{ {
const TorrentMeta *meta = m_torrent->meta(); const TorrentMeta *meta = m_torrent->meta();
int64_t beginPos = w.index * meta->pieceLength(); size_t beginPos = w.index * meta->pieceLength();
const uint8_t *buf = &w.data[0]; const uint8_t *buf = &w.data[0];
size_t length = w.data.size(); size_t length = w.data.size();
@@ -330,11 +341,11 @@ bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
if (beginPos < i.begin) if (beginPos < i.begin)
return false; return false;
int64_t fileEnd = i.begin + i.length; size_t fileEnd = i.begin + i.length;
if (beginPos >= fileEnd) if (beginPos >= fileEnd)
continue; continue;
int64_t amount = fileEnd - beginPos; size_t amount = fileEnd - beginPos;
if (amount > length) if (amount > length)
amount = length; amount = length;
@@ -345,6 +356,7 @@ bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
length -= wrote; length -= wrote;
} }
m_pendingBits.clear(w.index);
m_completedBits.set(w.index); m_completedBits.set(w.index);
g_sched.addEvent(std::bind(&Torrent::onPieceWriteComplete, m_torrent, w.from, w.index), 0); g_sched.addEvent(std::bind(&Torrent::onPieceWriteComplete, m_torrent, w.from, w.index), 0);
return true; return true;
@@ -358,7 +370,7 @@ size_t TorrentFileManagerImpl::get_next_piece(const std::function<bool (size_t)>
std::lock_guard<std::mutex> guard(m_mutex); std::lock_guard<std::mutex> guard(m_mutex);
for (size_t i = 0; i < m_pieces.size(); ++i) { for (size_t i = 0; i < m_pieces.size(); ++i) {
Piece *p = &m_pieces[i]; Piece *p = &m_pieces[i];
if (m_completedBits.test(i) || !fun(i)) if (m_completedBits.test(i) || m_pendingBits.test(i) || !fun(i))
continue; continue;
if (!p->pri) { if (!p->pri) {
@@ -437,11 +449,21 @@ size_t TorrentFileManager::computeDownloaded()
return i->compute_downloaded(); return i->compute_downloaded();
} }
size_t TorrentFileManager::pending() const
{
return i->pending();
}
bool TorrentFileManager::pieceDone(size_t index) const bool TorrentFileManager::pieceDone(size_t index) const
{ {
return i->piece_done(index); return i->piece_done(index);
} }
bool TorrentFileManager::piecePending(size_t index) const
{
return i->piece_pending(index);
}
bool TorrentFileManager::registerFiles(const std::string &baseDir, const TorrentFiles &files) bool TorrentFileManager::registerFiles(const std::string &baseDir, const TorrentFiles &files)
{ {
// We have to initialize pieces here // We have to initialize pieces here
@@ -488,7 +510,7 @@ bool TorrentFileManager::registerFiles(const std::string &baseDir, const Torrent
return true; return true;
} }
bool TorrentFileManager::requestPieceBlock(size_t index, uint32_t from, int64_t begin, int64_t size) bool TorrentFileManager::requestPieceBlock(size_t index, uint32_t from, size_t begin, size_t size)
{ {
static uint32_t rid = 0; static uint32_t rid = 0;
if (!i->intact(index) || !i->is_read_eligible(index, begin + size)) if (!i->intact(index) || !i->is_read_eligible(index, begin + size))

View File

@@ -33,8 +33,8 @@
struct TorrentFileInfo { struct TorrentFileInfo {
std::string path; std::string path;
size_t index; size_t index;
int64_t begin; size_t begin;
int64_t length; size_t length;
}; };
typedef std::vector<TorrentFileInfo> TorrentFiles; typedef std::vector<TorrentFileInfo> TorrentFiles;
@@ -46,6 +46,7 @@ public:
~TorrentFileManager(); ~TorrentFileManager();
const bitset *completedBits() const; const bitset *completedBits() const;
size_t pending() const;
size_t pieceSize(size_t index) const; size_t pieceSize(size_t index) const;
size_t completedPieces() const; size_t completedPieces() const;
size_t totalPieces() const; size_t totalPieces() const;
@@ -53,8 +54,9 @@ public:
size_t computeDownloaded(); size_t computeDownloaded();
bool pieceDone(size_t index) const; bool pieceDone(size_t index) const;
bool piecePending(size_t index) const;
bool registerFiles(const std::string &baseDir, const TorrentFiles &files); bool registerFiles(const std::string &baseDir, const TorrentFiles &files);
bool requestPieceBlock(size_t index, uint32_t from, int64_t begin, int64_t size); bool requestPieceBlock(size_t index, uint32_t from, size_t begin, size_t size);
bool writePieceBlock(size_t index, uint32_t from, DataBuffer<uint8_t> &&data); bool writePieceBlock(size_t index, uint32_t from, DataBuffer<uint8_t> &&data);
private: private:

View File

@@ -86,7 +86,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
sha1.get_digest(m_checkSum); sha1.get_digest(m_checkSum);
m_name = Bencode::cast<std::string>(info["name"]); m_name = Bencode::cast<std::string>(info["name"]);
m_pieceLength = Bencode::cast<int64_t>(info["piece length"]); m_pieceLength = Bencode::cast<size_t>(info["piece length"]);
std::string pieces = Bencode::cast<std::string>(info["pieces"]); std::string pieces = Bencode::cast<std::string>(info["pieces"]);
m_sha1sums.reserve(pieces.size() / 20); m_sha1sums.reserve(pieces.size() / 20);
@@ -111,7 +111,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
m_dirName = Bencode::cast<std::string>(info["name"]); m_dirName = Bencode::cast<std::string>(info["name"]);
size_t index = 0; size_t index = 0;
int64_t begin = 0; size_t begin = 0;
const boost::any &any = info["files"]; const boost::any &any = info["files"];
if (any.type() == typeid(Dictionary)) { if (any.type() == typeid(Dictionary)) {
@@ -119,7 +119,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
Dictionary v = Bencode::cast<Dictionary>(pair.second); Dictionary v = Bencode::cast<Dictionary>(pair.second);
VectorType pathList = Bencode::cast<VectorType>(v["path"]); VectorType pathList = Bencode::cast<VectorType>(v["path"]);
if (!parseFile(pathList, index, begin, Bencode::cast<int64_t>(v["length"]))) if (!parseFile(pathList, index, begin, Bencode::cast<size_t>(v["length"])))
return false; return false;
} }
} else if (any.type() == typeid(VectorType)) { } else if (any.type() == typeid(VectorType)) {
@@ -127,7 +127,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
Dictionary v = Bencode::cast<Dictionary>(f); Dictionary v = Bencode::cast<Dictionary>(f);
VectorType pathList = Bencode::cast<VectorType>(v["path"]); VectorType pathList = Bencode::cast<VectorType>(v["path"]);
if (!parseFile(pathList, index, begin, Bencode::cast<int64_t>(v["length"]))) if (!parseFile(pathList, index, begin, Bencode::cast<size_t>(v["length"])))
return false; return false;
} }
} else { } else {
@@ -135,7 +135,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
return false; return false;
} }
} else { } else {
int64_t length = Bencode::cast<int64_t>(info["length"]); size_t length = Bencode::cast<size_t>(info["length"]);
if (length <= 0) if (length <= 0)
return false; return false;
@@ -153,7 +153,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
return true; return true;
} }
bool TorrentMeta::parseFile(const VectorType &pathList, size_t &index, int64_t &begin, int64_t length) bool TorrentMeta::parseFile(const VectorType &pathList, size_t &index, size_t &begin, size_t length)
{ {
std::string path = ""; std::string path = "";
for (const boost::any &any : pathList) { for (const boost::any &any : pathList) {

View File

@@ -50,12 +50,12 @@ public:
inline VectorType trackers() const { return m_trackers; } inline VectorType trackers() const { return m_trackers; }
inline const uint32_t *checkSum() const { return &m_checkSum[0]; } inline const uint32_t *checkSum() const { return &m_checkSum[0]; }
inline int64_t pieceLength() const { return m_pieceLength; } inline size_t pieceLength() const { return m_pieceLength; }
inline size_t totalSize() const { return m_totalSize; } inline size_t totalSize() const { return m_totalSize; }
protected: protected:
bool internalParse(Dictionary &d, Bencode &b); bool internalParse(Dictionary &d, Bencode &b);
bool parseFile(const VectorType &pathList, size_t &index, int64_t &begin, int64_t length); bool parseFile(const VectorType &pathList, size_t &index, size_t &begin, size_t length);
private: private:
std::string m_dirName; std::string m_dirName;
@@ -65,7 +65,7 @@ private:
std::string m_mainTracker; std::string m_mainTracker;
uint32_t m_checkSum[5]; uint32_t m_checkSum[5];
int64_t m_pieceLength; size_t m_pieceLength;
size_t m_totalSize; size_t m_totalSize;
TorrentFiles m_files; TorrentFiles m_files;

View File

@@ -136,7 +136,7 @@ bool Tracker::httpRequest(const TrackerQuery &r)
} }
m_timeToNextRequest = std::chrono::system_clock::now() m_timeToNextRequest = std::chrono::system_clock::now()
+ std::chrono::milliseconds(Bencode::cast<int64_t>(dict["interval"])); + std::chrono::seconds(Bencode::cast<int64_t>(dict["interval"]));
m_torrent->connectToPeers(dict["peers"]); m_torrent->connectToPeers(dict["peers"]);
return true; return true;
} }
@@ -246,7 +246,7 @@ bool Tracker::udpRequest(const TrackerQuery &r)
return false; return false;
} }
m_timeToNextRequest = std::chrono::system_clock::now() + std::chrono::milliseconds(readBE32(&response[8])); m_timeToNextRequest = std::chrono::system_clock::now() + std::chrono::seconds(readBE32(&response[8]));
m_torrent->rawConnectPeers(&response[20], len - 20); m_torrent->rawConnectPeers(&response[20], len - 20);
return true; return true;
} }

View File

@@ -27,13 +27,16 @@
#include <functional> #include <functional>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <fstream>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#ifndef _WIN32 #ifndef _WIN32
#include <ncurses.h> #include <ncurses.h>
#endif #endif
/* Externed */
std::ofstream logfile;
#ifdef _WIN32 #ifdef _WIN32
enum { enum {
COL_BLACK = 0, COL_BLACK = 0,
@@ -75,15 +78,15 @@ enum {
static void print_stats(Torrent *t) static void print_stats(Torrent *t)
{ {
const TorrentMeta *meta = t->meta(); TorrentMeta *meta = t->meta();
const TorrentFileManager *fm = t->fileManager(); TorrentFileManager *fm = t->fileManager();
printc(COL_GREEN, "%s: ", meta->name().c_str()); printc(COL_GREEN, "%s: ", meta->name().c_str());
printc(COL_YELLOW, "%.2f Mbps (%zd/%zd MB) [ %zd hash miss - %zd wasted - %.2f minutes left ] ", printc(COL_YELLOW, "%.2f Mbps (%zd/%zd MB) [ %zd uploaded - %zd hash miss - %zd wasted - %.2f seconds left ] ",
t->downloadSpeed(), t->computeDownloaded() / 1024 / 1024, meta->totalSize() / 1024 / 1024, t->downloadSpeed(), t->computeDownloaded() / 1024 / 1024, meta->totalSize() / 1024 / 1024,
t->hashMisses(), t->wastedBytes(), t->eta() / 60); t->uploadedBytes(), t->hashMisses(), t->wastedBytes(), t->eta());
printc(COL_YELLOW, "[ %zd/%zd pieces %zd peers active ]\n", printc(COL_YELLOW, "[ %zd/%zd/%zd pieces %zd peers active ]\n",
fm->completedPieces(), fm->totalPieces(), t->activePeers()); fm->completedPieces(), fm->pending(), fm->totalPieces(), t->activePeers());
} }
static void print_all_stats(Torrent *torrents, size_t total) static void print_all_stats(Torrent *torrents, size_t total)
@@ -109,10 +112,12 @@ static void print_all_stats(Torrent *torrents, size_t total)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
bool noseed = false; bool noseed = true;
bool nodownload = false; bool nodownload = false;
int startport = 6881; int startport = 6881;
size_t max_peers = 15;
std::string dldir = "Torrents"; std::string dldir = "Torrents";
std::string lfname = "ctorrent.log";
std::vector<std::string> files; std::vector<std::string> files;
namespace po = boost::program_options; namespace po = boost::program_options;
@@ -121,10 +126,12 @@ int main(int argc, char *argv[])
("version,v", "print version string") ("version,v", "print version string")
("help,h", "print this help message") ("help,h", "print this help message")
("port,p", po::value(&startport), "specify start port for seeder torrents") ("port,p", po::value(&startport), "specify start port for seeder torrents")
("peers,m", po::value(&max_peers), "maximum amount of peers to feel sufficient with")
("nodownload,n", po::bool_switch(&nodownload), "do not download anything, just print info about torrents") ("nodownload,n", po::bool_switch(&nodownload), "do not download anything, just print info about torrents")
("piecesize,s", po::value(&maxRequestSize), "specify piece block size") ("piecesize,s", po::value(&maxRequestSize), "specify piece block size")
("dldir,d", po::value(&dldir), "specify downloads directory") ("dldir,d", po::value(&dldir), "specify downloads directory")
("noseed,e", po::bool_switch(&noseed), "do not seed after download has finished.") ("noseed,e", po::bool_switch(&noseed), "do not seed after download has finished.")
("log,l", po::value(&lfname), "specify log file name")
("torrents,t", po::value<std::vector<std::string>>(&files)->required()->multitoken(), "specify torrent file(s)"); ("torrents,t", po::value<std::vector<std::string>>(&files)->required()->multitoken(), "specify torrent file(s)");
if (argc == 1) { if (argc == 1) {
@@ -158,6 +165,12 @@ int main(int argc, char *argv[])
if (vm.count("piecesize")) if (vm.count("piecesize"))
maxRequestSize = 1 << (32 - __builtin_clz(maxRequestSize - 1)); maxRequestSize = 1 << (32 - __builtin_clz(maxRequestSize - 1));
logfile.open(lfname, std::ios_base::trunc | std::ios_base::out);
if (!logfile.is_open()) {
std::cerr << "Cannot open log file " << lfname << ": " << errno << std::endl;
return 1;
}
size_t total = files.size(); size_t total = files.size();
size_t total_bits = 0; size_t total_bits = 0;
size_t completed = 0; size_t completed = 0;
@@ -221,12 +234,17 @@ int main(int argc, char *argv[])
std::clog << "Downloading torrents..." << std::endl; std::clog << "Downloading torrents..." << std::endl;
while (total_bits ^ (completed | errors)) { while (total_bits ^ (completed | errors)) {
for (size_t i = 0; i < total; ++i) { for (size_t i = 0; i < total; ++i) {
if (errors & (1 << i))
continue;
Torrent *t = &torrents[i]; Torrent *t = &torrents[i];
if (t->isFinished()) { if (t->isFinished()) {
t->finish(); if (!noseed)
t->finish();
completed |= 1 << i; completed |= 1 << i;
} else { } else {
t->checkTrackers(); //if (t->activePeers() < max_peers)
t->checkTrackers();
if (!noseed) if (!noseed)
t->nextConnection(); t->nextConnection();
} }
@@ -249,7 +267,7 @@ int main(int argc, char *argv[])
while (eseed ^ total_bits) { while (eseed ^ total_bits) {
for (size_t i = 0; i < total; ++i) { for (size_t i = 0; i < total; ++i) {
Torrent *t = &torrents[i]; Torrent *t = &torrents[i];
if (!t->nextConnection() || !t->checkTrackers()) if (!t->nextConnection() || (t->activePeers() < max_peers && !t->checkTrackers()))
eseed |= 1 << i; eseed |= 1 << i;
} }
@@ -276,6 +294,7 @@ int main(int argc, char *argv[])
} }
delete []torrents; delete []torrents;
logfile.close();
return 0; return 0;
} }

View File

@@ -79,16 +79,10 @@ public:
size_t popcnt(uint64_t v) const size_t popcnt(uint64_t v) const
{ {
#ifdef __GNUC__
return __builtin_popcount(v);
#elif _MSC_VER
return __popcnt64(v);
#else
// Hamming Weight // Hamming Weight
v = v - ((v >> 1) & 0x5555555555555555); v = v - ((v >> 1) & 0x5555555555555555);
v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333); v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333);
return (((v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F) * 0x0101010101010101) >> 56; return (((v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F) * 0x0101010101010101) >> 56;
#endif
} }
size_t size() const { return m_size; } size_t size() const { return m_size; }
@@ -107,7 +101,7 @@ public:
src += 4; src += 4;
} }
if (src + 1 < dst) { if (src + 1 <= dst) {
set += popcnt(*(uint16_t *)src); set += popcnt(*(uint16_t *)src);
src += 2; src += 2;
} }