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:
4
Makefile
4
Makefile
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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; }
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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))
|
||||
|
@@ -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:
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
41
main.cpp
41
main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user