diff --git a/libtransmission/torrent-magnet.cc b/libtransmission/torrent-magnet.cc index 95bd16c9e..e1101165d 100644 --- a/libtransmission/torrent-magnet.cc +++ b/libtransmission/torrent-magnet.cc @@ -6,10 +6,10 @@ #include #include /* INT_MAX */ #include +#include #include #include - -#include +#include #include @@ -27,9 +27,6 @@ #include "tr-assert.h" #include "utils.h" #include "variant.h" -#include "web-utils.h" - -using namespace std::literals; /*** **** @@ -40,26 +37,32 @@ static auto constexpr MinRepeatIntervalSecs = int{ 3 }; struct metadata_node { - time_t requestedAt; - int piece; + time_t requested_at = 0U; + int piece = 0; }; struct tr_incomplete_metadata { - char* metadata; - size_t metadata_size; - int pieceCount; + std::vector metadata; /** sorted from least to most recently requested */ - struct metadata_node* piecesNeeded; - int piecesNeededCount; + std::deque pieces_needed; + + int piece_count = 0; }; -static void incompleteMetadataFree(struct tr_incomplete_metadata* m) +static auto create_all_needed(int n_pieces) { - tr_free(m->metadata); - tr_free(m->piecesNeeded); - tr_free(m); + auto ret = std::deque{}; + + ret.resize(n_pieces); + + for (int i = 0; i < n_pieces; ++i) + { + ret[i].piece = i; + } + + return ret; } bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t size) @@ -83,31 +86,23 @@ bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t size) return false; } - auto* const m = tr_new(struct tr_incomplete_metadata, 1); + auto* const m = new tr_incomplete_metadata{}; if (m == nullptr) { return false; } - m->pieceCount = n; - m->metadata = tr_new(char, size); - m->metadata_size = size; - m->piecesNeededCount = n; - m->piecesNeeded = tr_new(struct metadata_node, n); + m->piece_count = n; + m->metadata.resize(size); + m->pieces_needed = create_all_needed(n); - if (m->metadata == nullptr || m->piecesNeeded == nullptr) + if (std::empty(m->metadata) || std::empty(m->pieces_needed)) { - incompleteMetadataFree(m); + delete m; return false; } - for (int i = 0; i < n; ++i) - { - m->piecesNeeded[i].piece = i; - m->piecesNeeded[i].requestedAt = 0; - } - tor->incompleteMetadata = m; return true; } @@ -158,23 +153,10 @@ void* tr_torrentGetMetadataPiece(tr_torrent const* tor, int piece, size_t* len) return ret; } -static int getPieceNeededIndex(struct tr_incomplete_metadata const* m, int piece) -{ - for (int i = 0; i < m->piecesNeededCount; ++i) - { - if (m->piecesNeeded[i].piece == piece) - { - return i; - } - } - - return -1; -} - static int getPieceLength(struct tr_incomplete_metadata const* m, int piece) { - return piece + 1 == m->pieceCount ? // last piece - m->metadata_size - (piece * METADATA_PIECE_SIZE) : + return piece + 1 == m->piece_count ? // last piece + std::size(m->metadata) - (piece * METADATA_PIECE_SIZE) : METADATA_PIECE_SIZE; } @@ -256,7 +238,7 @@ bool tr_torrentUseMetainfoFromFile( if (tor->incompleteMetadata != nullptr) { - incompleteMetadataFree(tor->incompleteMetadata); + delete tor->incompleteMetadata; tor->incompleteMetadata = nullptr; } tor->isStopping = true; @@ -273,7 +255,7 @@ bool tr_torrentUseMetainfoFromFile( static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_error** error) { // test the info_dict checksum - auto const sha1 = tr_sha1(std::string_view{ m->metadata, m->metadata_size }); + auto const sha1 = tr_sha1(m->metadata); if (bool const checksum_passed = sha1 && *sha1 == tor->infoHash(); !checksum_passed) { return false; @@ -284,7 +266,7 @@ static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_ if (!tr_variantFromBuf( &info_dict_v, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, - { m->metadata, m->metadata_size }, + { std::data(m->metadata), std::size(m->metadata) }, nullptr, error)) { @@ -326,7 +308,7 @@ static void onHaveAllMetainfo(tr_torrent* tor, tr_incomplete_metadata* m) tr_error* error = nullptr; if (useNewMetainfo(tor, m, &error)) { - incompleteMetadataFree(tor->incompleteMetadata); + delete tor->incompleteMetadata; tor->incompleteMetadata = nullptr; tor->isStopping = true; tor->magnetVerify = true; @@ -338,15 +320,10 @@ static void onHaveAllMetainfo(tr_torrent* tor, tr_incomplete_metadata* m) } else /* drat. */ { - int const n = m->pieceCount; + int const n = m->piece_count; - for (int i = 0; i < n; ++i) - { - m->piecesNeeded[i].piece = i; - m->piecesNeeded[i].requestedAt = 0; - } + m->pieces_needed = create_all_needed(n); - m->piecesNeededCount = n; char const* const msg = error != nullptr && error->message != nullptr ? error->message : "unknown error"; tr_logAddWarnTor( tor, @@ -377,7 +354,7 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, in } // sanity test: is `piece` in range? - if ((piece < 0) || (piece >= m->pieceCount)) + if ((piece < 0) || (piece >= m->piece_count)) { return; } @@ -389,22 +366,24 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, in } // do we need this piece? - int const idx = getPieceNeededIndex(m, piece); - if (idx == -1) + auto& needed = m->pieces_needed; + auto const iter = std::find_if( + std::begin(needed), + std::end(needed), + [piece](auto const& item) { return item.piece == piece; }); + if (iter == std::end(needed)) { return; } size_t const offset = piece * METADATA_PIECE_SIZE; - std::copy_n(reinterpret_cast(data), len, m->metadata + offset); + std::copy_n(reinterpret_cast(data), len, std::begin(m->metadata) + offset); - tr_removeElementFromArray(m->piecesNeeded, idx, sizeof(struct metadata_node), m->piecesNeededCount); - --m->piecesNeededCount; + needed.erase(iter); + tr_logAddDebugTor(tor, fmt::format("saving metainfo piece {}... {} remain", piece, std::size(needed))); - tr_logAddDebugTor(tor, fmt::format("saving metainfo piece {}... {} remain", piece, m->piecesNeededCount)); - - /* are we done? */ - if (m->piecesNeededCount == 0) + // are we done? + if (std::empty(needed)) { tr_logAddDebugTor(tor, fmt::format("metainfo piece {} was the last one", piece)); onHaveAllMetainfo(tor, m); @@ -418,17 +397,16 @@ bool tr_torrentGetNextMetadataRequest(tr_torrent* tor, time_t now, int* setme_pi bool have_request = false; struct tr_incomplete_metadata* m = tor->incompleteMetadata; - if (m != nullptr && m->piecesNeededCount > 0 && m->piecesNeeded[0].requestedAt + MinRepeatIntervalSecs < now) + auto& needed = m->pieces_needed; + if (m != nullptr && !std::empty(needed) && needed.front().requested_at + MinRepeatIntervalSecs < now) { - int const piece = m->piecesNeeded[0].piece; - tr_removeElementFromArray(m->piecesNeeded, 0, sizeof(struct metadata_node), m->piecesNeededCount); + auto req = needed.front(); + needed.pop_front(); + req.requested_at = now; + needed.push_back(req); - int const i = m->piecesNeededCount - 1; - m->piecesNeeded[i].piece = piece; - m->piecesNeeded[i].requestedAt = now; - - tr_logAddDebugTor(tor, fmt::format("next piece to request: {}", piece)); - *setme_piece = piece; + tr_logAddDebugTor(tor, fmt::format("next piece to request: {}", req.piece)); + *setme_piece = req.piece; have_request = true; } @@ -443,7 +421,7 @@ double tr_torrentGetMetadataPercent(tr_torrent const* tor) } auto const* const m = tor->incompleteMetadata; - return m == nullptr || m->pieceCount == 0 ? 0.0 : (m->pieceCount - m->piecesNeededCount) / (double)m->pieceCount; + return m == nullptr || m->piece_count == 0 ? 0.0 : (m->piece_count - std::size(m->pieces_needed)) / (double)m->piece_count; } char* tr_torrentGetMagnetLink(tr_torrent const* tor)