1
0
mirror of https://github.com/asamy/ctorrent synced 2025-10-05 15:42:48 +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
CXX = $(CROSS_BUILD)g++
BTYPE = -O3
BTYPE = -O0 -g
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
ifeq ($(OS),Windows_NT)

View File

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

View File

@@ -97,7 +97,7 @@ void Peer::verify()
m_peerId = peerId;
m_conn->write(m_handshake, 68);
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));
});
}
@@ -226,7 +226,7 @@ void Peer::handleMessage(MessageType messageType, InputMessage in)
return handleError("received too big piece block of size " + bytesToHumanReadable(payloadSize, true));
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())
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);
delete piece;
} else {
PieceBlock *block = &piece->blocks[blockIndex];
uint8_t *payload = in.getBuffer(payloadSize);
if (block->rpos != 0) {
memcpy(block->data, payload, std::max(payloadSize, block->size - block->rpos));
free(payload);
block->rpos += payloadSize;
} else {
block->size = block->rpos = payloadSize;
block->data = payload;
++piece->currentBlocks;
}
PieceBlock *block = &piece->blocks[blockIndex];
block->size = payloadSize;
block->data = payload;
++piece->currentBlocks;
if (piece->currentBlocks == piece->numBlocks) {
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
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())
return;

View File

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

View File

@@ -30,6 +30,9 @@
#include <iostream>
#include <thread>
#include <random>
#include <fstream>
extern std::ofstream logfile;
Torrent::Torrent()
: m_listener(nullptr),
@@ -159,12 +162,10 @@ bool Torrent::checkTrackers()
bool Torrent::nextConnection()
{
if (m_listener) {
m_listener->accept(
[this] (const ConnectionPtr &c) {
auto peer = std::make_shared<Peer>(c, this);
peer->verify();
}
);
m_listener->accept([this] (const ConnectionPtr &c) {
auto peer = std::make_shared<Peer>(c, this);
peer->verify();
});
return true;
}
@@ -175,7 +176,7 @@ bool Torrent::nextConnection()
bool Torrent::queryTrackers(const TrackerQuery &query, uint16_t port)
{
bool success = queryTracker(m_meta.tracker(), query, port);
if (m_meta.trackers().empty())
if (success)
return success;
for (const boost::any &s : m_meta.trackers()) {
@@ -186,10 +187,10 @@ bool Torrent::queryTrackers(const TrackerQuery &query, uint16_t port)
return true;
} else if (s.type() == typeid(std::string) &&
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)
@@ -293,6 +294,7 @@ void Torrent::addPeer(const PeerPtr &peer)
if (it != m_blacklisted.end())
m_blacklisted.erase(it);
logfile << peer->getIP() << ": now connected" << std::endl;
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());
if (it != m_peers.end())
m_peers.erase(it);
logfile << peer->getIP() << ": closing: " << errmsg << std::endl;
}
void Torrent::disconnectPeers()
@@ -325,51 +329,58 @@ void Torrent::sendBitfield(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())
peer->sendPieceRequest(index);
}
bool Torrent::handlePieceCompleted(const PeerPtr &peer, uint32_t index, DataBuffer<uint8_t> &&data)
{
uint32_t downloaded = data.size();
if (m_fileManager.writePieceBlock(index, peer->ip(), std::move(data))) {
m_downloadedBytes += downloaded;
logfile << peer->getIP() << ": finished downloading piece: " << index << std::endl;
if (m_fileManager.writePieceBlock(index, peer->ip(), std::move(data)))
return true;
}
m_wastedBytes += downloaded;
m_wastedBytes += data.size();
++m_hashMisses;
return false;
}
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);
}
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)
if (!it.second->hasPiece(index))
if (it.second->ip() != from && !it.second->hasPiece(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);
if (it != m_peers.end()) {
it->second->sendPieceBlock(index, begin, block, size);
m_uploadedBytes += size;
}
delete []block;
}
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)
{
logfile << peer->getIP() << ": " << msg << std::endl;
}
void Torrent::handleNewPeer(const PeerPtr &peer)

View File

@@ -76,10 +76,10 @@ public:
clock_t elapsed();
// 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
const TorrentFileManager *fileManager() const { return &m_fileManager; }
TorrentFileManager *fileManager() { return &m_fileManager; }
protected:
bool queryTrackers(const TrackerQuery &r, uint16_t port);
@@ -108,8 +108,8 @@ protected:
public:
// TorrentFileManager -> Torrent
void onPieceWriteComplete(uint32_t from, uint32_t index);
void onPieceReadComplete(uint32_t from, uint32_t index, uint32_t begin, uint8_t *block, size_t size);
void onPieceWriteComplete(uint32_t from, size_t index);
void onPieceReadComplete(uint32_t from, size_t index, int64_t begin, uint8_t *block, size_t size);
private:
Server *m_listener;

View File

@@ -44,8 +44,8 @@ struct ReadRequest {
size_t index;
uint32_t id;
uint32_t from;
int64_t begin;
int64_t size;
size_t begin;
size_t size;
};
struct LeastReadRequest {
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 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 scan_file(const TorrentFile &f);
void scan_pieces();
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 total_pieces() const { return m_pieces.size(); }
size_t get_next_piece(const std::function<bool (size_t)> &fun);
size_t compute_downloaded();
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 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 {
if (m_pendingBits.test(index))
return false;
boost::uuids::detail::sha1 sha1;
sha1.process_bytes(data, size);
@@ -133,6 +138,7 @@ public:
auto sha1sums = m_torrent->meta()->sha1sums();
m_pieces.reserve(sha1sums.size());
m_completedBits.construct(sha1sums.size());
m_pendingBits.construct(sha1sums.size());
for (sha1sum s : sha1sums)
m_pieces.push_back(Piece(s));
@@ -149,6 +155,8 @@ private:
std::queue<WriteRequest> m_writeRequests;
bitset m_completedBits;
bitset m_pendingBits;
std::vector<TorrentFile> m_files;
std::vector<Piece> m_pieces;
@@ -165,11 +173,11 @@ void TorrentFileManagerImpl::scan_file(const TorrentFile &f)
{
FILE *fp = f.fp;
fseek(fp, 0L, SEEK_END);
off64_t fileLength = ftello64(fp);
size_t fileLength = ftello64(fp);
fseek(fp, 0L, SEEK_SET);
if (f.info.length > fileLength) {
// truncate(f.info.path.c_str(), f.info.length);
truncate(f.info.path.c_str(), f.info.length);
return;
}
@@ -267,14 +275,18 @@ void TorrentFileManagerImpl::thread()
// mark the piece as fully have before we fully wrote it to disk.
while (!m_writeRequests.empty() && !m_stopped) {
const WriteRequest &w = m_writeRequests.front();
if (process_write(w))
m_writeRequests.pop();
if (!process_write(w))
break;
m_writeRequests.pop();
}
while (!m_readRequests.empty() && !m_stopped) {
ReadRequest r = m_readRequests.top();
if (process_read(r))
m_readRequests.pop();
if (!process_read(r))
break;
m_readRequests.pop();
}
lock.unlock();
@@ -286,16 +298,16 @@ bool TorrentFileManagerImpl::process_read(const ReadRequest &r)
const TorrentMeta *meta = m_torrent->meta();
int64_t blockBegin = r.begin + r.index * meta->pieceLength();
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) {
int64_t filePos = blockBegin + writePos;
const TorrentFileInfo &i = f.info;
size_t filePos = blockBegin + writePos;
if (filePos < i.begin)
return false;
int64_t fileEnd = i.begin + i.length;
size_t fileEnd = i.begin + i.length;
if (filePos > fileEnd)
continue;
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
m_torrent->onPieceReadComplete(r.from, r.index, r.begin, block, r.size);
g_sched.addEvent(std::bind(&Torrent::onPieceReadComplete, m_torrent, r.from, r.index, r.begin, block, r.size), 0);
return true;
}
bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
{
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];
size_t length = w.data.size();
@@ -330,11 +341,11 @@ bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
if (beginPos < i.begin)
return false;
int64_t fileEnd = i.begin + i.length;
size_t fileEnd = i.begin + i.length;
if (beginPos >= fileEnd)
continue;
int64_t amount = fileEnd - beginPos;
size_t amount = fileEnd - beginPos;
if (amount > length)
amount = length;
@@ -345,6 +356,7 @@ bool TorrentFileManagerImpl::process_write(const WriteRequest &w)
length -= wrote;
}
m_pendingBits.clear(w.index);
m_completedBits.set(w.index);
g_sched.addEvent(std::bind(&Torrent::onPieceWriteComplete, m_torrent, w.from, w.index), 0);
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);
for (size_t i = 0; i < m_pieces.size(); ++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;
if (!p->pri) {
@@ -437,11 +449,21 @@ size_t TorrentFileManager::computeDownloaded()
return i->compute_downloaded();
}
size_t TorrentFileManager::pending() const
{
return i->pending();
}
bool TorrentFileManager::pieceDone(size_t index) const
{
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)
{
// We have to initialize pieces here
@@ -488,7 +510,7 @@ bool TorrentFileManager::registerFiles(const std::string &baseDir, const Torrent
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;
if (!i->intact(index) || !i->is_read_eligible(index, begin + size))

View File

@@ -33,8 +33,8 @@
struct TorrentFileInfo {
std::string path;
size_t index;
int64_t begin;
int64_t length;
size_t begin;
size_t length;
};
typedef std::vector<TorrentFileInfo> TorrentFiles;
@@ -46,6 +46,7 @@ public:
~TorrentFileManager();
const bitset *completedBits() const;
size_t pending() const;
size_t pieceSize(size_t index) const;
size_t completedPieces() const;
size_t totalPieces() const;
@@ -53,8 +54,9 @@ public:
size_t computeDownloaded();
bool pieceDone(size_t index) const;
bool piecePending(size_t index) const;
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);
private:

View File

@@ -86,7 +86,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
sha1.get_digest(m_checkSum);
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"]);
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"]);
size_t index = 0;
int64_t begin = 0;
size_t begin = 0;
const boost::any &any = info["files"];
if (any.type() == typeid(Dictionary)) {
@@ -119,7 +119,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
Dictionary v = Bencode::cast<Dictionary>(pair.second);
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;
}
} else if (any.type() == typeid(VectorType)) {
@@ -127,7 +127,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
Dictionary v = Bencode::cast<Dictionary>(f);
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;
}
} else {
@@ -135,7 +135,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
return false;
}
} else {
int64_t length = Bencode::cast<int64_t>(info["length"]);
size_t length = Bencode::cast<size_t>(info["length"]);
if (length <= 0)
return false;
@@ -153,7 +153,7 @@ bool TorrentMeta::internalParse(Dictionary &dict, Bencode &bencode)
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 = "";
for (const boost::any &any : pathList) {

View File

@@ -50,12 +50,12 @@ public:
inline VectorType trackers() const { return m_trackers; }
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; }
protected:
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:
std::string m_dirName;
@@ -65,7 +65,7 @@ private:
std::string m_mainTracker;
uint32_t m_checkSum[5];
int64_t m_pieceLength;
size_t m_pieceLength;
size_t m_totalSize;
TorrentFiles m_files;

View File

@@ -136,7 +136,7 @@ bool Tracker::httpRequest(const TrackerQuery &r)
}
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"]);
return true;
}
@@ -246,7 +246,7 @@ bool Tracker::udpRequest(const TrackerQuery &r)
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);
return true;
}

View File

@@ -27,13 +27,16 @@
#include <functional>
#include <chrono>
#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#ifndef _WIN32
#include <ncurses.h>
#endif
/* Externed */
std::ofstream logfile;
#ifdef _WIN32
enum {
COL_BLACK = 0,
@@ -75,15 +78,15 @@ enum {
static void print_stats(Torrent *t)
{
const TorrentMeta *meta = t->meta();
const TorrentFileManager *fm = t->fileManager();
TorrentMeta *meta = t->meta();
TorrentFileManager *fm = t->fileManager();
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->hashMisses(), t->wastedBytes(), t->eta() / 60);
printc(COL_YELLOW, "[ %zd/%zd pieces %zd peers active ]\n",
fm->completedPieces(), fm->totalPieces(), t->activePeers());
t->uploadedBytes(), t->hashMisses(), t->wastedBytes(), t->eta());
printc(COL_YELLOW, "[ %zd/%zd/%zd pieces %zd peers active ]\n",
fm->completedPieces(), fm->pending(), fm->totalPieces(), t->activePeers());
}
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[])
{
bool noseed = false;
bool noseed = true;
bool nodownload = false;
int startport = 6881;
size_t max_peers = 15;
std::string dldir = "Torrents";
std::string lfname = "ctorrent.log";
std::vector<std::string> files;
namespace po = boost::program_options;
@@ -121,10 +126,12 @@ int main(int argc, char *argv[])
("version,v", "print version string")
("help,h", "print this help message")
("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")
("piecesize,s", po::value(&maxRequestSize), "specify piece block size")
("dldir,d", po::value(&dldir), "specify downloads directory")
("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)");
if (argc == 1) {
@@ -158,6 +165,12 @@ int main(int argc, char *argv[])
if (vm.count("piecesize"))
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_bits = 0;
size_t completed = 0;
@@ -221,12 +234,17 @@ int main(int argc, char *argv[])
std::clog << "Downloading torrents..." << std::endl;
while (total_bits ^ (completed | errors)) {
for (size_t i = 0; i < total; ++i) {
if (errors & (1 << i))
continue;
Torrent *t = &torrents[i];
if (t->isFinished()) {
t->finish();
if (!noseed)
t->finish();
completed |= 1 << i;
} else {
t->checkTrackers();
//if (t->activePeers() < max_peers)
t->checkTrackers();
if (!noseed)
t->nextConnection();
}
@@ -249,7 +267,7 @@ int main(int argc, char *argv[])
while (eseed ^ total_bits) {
for (size_t i = 0; i < total; ++i) {
Torrent *t = &torrents[i];
if (!t->nextConnection() || !t->checkTrackers())
if (!t->nextConnection() || (t->activePeers() < max_peers && !t->checkTrackers()))
eseed |= 1 << i;
}
@@ -276,6 +294,7 @@ int main(int argc, char *argv[])
}
delete []torrents;
logfile.close();
return 0;
}

View File

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