diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 2389f841b..b9361b59e 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 558699542570759E00F77A43 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55869925257074EC00F77A43 /* libcurl.tbd */; }; 558699602570759F00F77A43 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55869925257074EC00F77A43 /* libcurl.tbd */; }; 5586996C2570759F00F77A43 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55869925257074EC00F77A43 /* libcurl.tbd */; }; + 62F644738FE3D8788EBF73A9 /* block-info.cc in Sources */ = {isa = PBXBuildFile; fileRef = A54D44C6A7AAF131D9AE29F5 /* block-info.cc */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.mm */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; @@ -366,6 +367,7 @@ ED8A16412735A8AA000D61F9 /* peer-mgr-wishlist.h in Headers */ = {isa = PBXBuildFile; fileRef = ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */; }; ED8A16422735A8AA000D61F9 /* peer-mgr-wishlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */; }; EDBDFA9E25AFCCA60093D9C1 /* evutil_time.c in Sources */ = {isa = PBXBuildFile; fileRef = EDBDFA9D25AFCCA60093D9C1 /* evutil_time.c */; }; + F11545ACA7C4D7A464F703AB /* block-info.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A044CBD8C049AFCBD4DB411 /* block-info.h */; settings = {ATTRIBUTES = (Project, ); }; }; F63480631E1D7274005B9E09 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63480621E1D7274005B9E09 /* Images.xcassets */; }; /* End PBXBuildFile section */ @@ -518,10 +520,6 @@ 4D36BA660CA2F00800A63CA5 /* peer-io.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "peer-io.h"; sourceTree = ""; }; 4D36BA680CA2F00800A63CA5 /* peer-mgr.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr.cc"; sourceTree = ""; }; 4D36BA690CA2F00800A63CA5 /* peer-mgr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "peer-mgr.h"; sourceTree = ""; }; - ED8A163B2735A8AA000D61F9 /* peer-mgr-active-requests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "peer-mgr-active-requests.h"; sourceTree = ""; }; - ED8A163C2735A8AA000D61F9 /* peer-mgr-active-requests.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-active-requests.cc"; sourceTree = ""; }; - ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "peer-mgr-wishlist.h"; sourceTree = ""; }; - ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-wishlist.cc"; sourceTree = ""; }; 4D36BA6A0CA2F00800A63CA5 /* peer-msgs.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-msgs.cc"; sourceTree = ""; }; 4D36BA6B0CA2F00800A63CA5 /* peer-msgs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "peer-msgs.h"; sourceTree = ""; }; 4D36BA6C0CA2F00800A63CA5 /* ptrarray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ptrarray.h; sourceTree = ""; }; @@ -544,6 +542,7 @@ 4DFBC2DD09C0970D00D5C571 /* Torrent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Torrent.h; sourceTree = ""; }; 4DFBC2DE09C0970D00D5C571 /* Torrent.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Torrent.mm; sourceTree = ""; }; 55869925257074EC00F77A43 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; + 6A044CBD8C049AFCBD4DB411 /* block-info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "block-info.h"; path = "block-info.h"; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Transmission.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Transmission.app; sourceTree = BUILT_PRODUCTS_DIR; }; A200B8390A2263BA007BBB1E /* InfoWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoWindowController.h; sourceTree = ""; }; @@ -938,6 +937,7 @@ A2FB07F115F8208300933543 /* nl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; A2FB701A0D95CAEA0001F331 /* GroupsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GroupsController.h; sourceTree = ""; }; A2FB701B0D95CAEA0001F331 /* GroupsController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GroupsController.mm; sourceTree = ""; }; + A54D44C6A7AAF131D9AE29F5 /* block-info.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = block-info.cc; sourceTree = ""; }; BE1183480CE160960002D0F3 /* libminiupnp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminiupnp.a; sourceTree = BUILT_PRODUCTS_DIR; }; BE11834E0CE160C50002D0F3 /* miniupnpc_declspec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = miniupnpc_declspec.h; sourceTree = ""; }; BE11834F0CE160C50002D0F3 /* igd_desc_parse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = igd_desc_parse.h; sourceTree = ""; }; @@ -1028,6 +1028,10 @@ CAB35C62252F6F5E00552A55 /* mime-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mime-types.h"; sourceTree = ""; }; E138A9750C04D88F00C5426C /* ProgressGradients.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgressGradients.h; sourceTree = ""; }; E138A9760C04D88F00C5426C /* ProgressGradients.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ProgressGradients.mm; sourceTree = ""; }; + ED8A163B2735A8AA000D61F9 /* peer-mgr-active-requests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "peer-mgr-active-requests.h"; sourceTree = ""; }; + ED8A163C2735A8AA000D61F9 /* peer-mgr-active-requests.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-active-requests.cc"; sourceTree = ""; }; + ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "peer-mgr-wishlist.h"; sourceTree = ""; }; + ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-wishlist.cc"; sourceTree = ""; }; EDBDFA9D25AFCCA60093D9C1 /* evutil_time.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = evutil_time.c; sourceTree = ""; }; F63480621E1D7274005B9E09 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Images/Images.xcassets; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1374,6 +1378,8 @@ 4D1838DC09DEC04A0047D688 /* libtransmission */ = { isa = PBXGroup; children = ( + A54D44C6A7AAF131D9AE29F5 /* block-info.cc */, + 6A044CBD8C049AFCBD4DB411 /* block-info.h */, C17740D3273A002C00E455D2 /* web-utils.cc */, C17740D4273A002C00E455D2 /* web-utils.h */, CAB35C62252F6F5E00552A55 /* mime-types.h */, @@ -1898,6 +1904,7 @@ A2EA52321686AC0D00180493 /* quark.h in Headers */, A2AF23C916B44FA0003BC59E /* log.h in Headers */, A23FAE55178BC2950053DC5B /* platform-quota.h in Headers */, + F11545ACA7C4D7A464F703AB /* block-info.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2493,6 +2500,7 @@ A2EA52311686AC0D00180493 /* quark.cc in Sources */, A2AF23C816B44FA0003BC59E /* log.cc in Sources */, A23FAE54178BC2950053DC5B /* platform-quota.cc in Sources */, + 62F644738FE3D8788EBF73A9 /* block-info.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/libtransmission/CMakeLists.txt b/libtransmission/CMakeLists.txt index 8e1386acd..5efdc8468 100644 --- a/libtransmission/CMakeLists.txt +++ b/libtransmission/CMakeLists.txt @@ -6,27 +6,28 @@ configure_file( ) set(PROJECT_FILES - announcer.cc announcer-http.cc announcer-udp.cc + announcer.cc bandwidth.cc bitfield.cc + block-info.cc blocklist.cc cache.cc clients.cc completion.cc - crypto.cc - crypto-utils.cc crypto-utils-ccrypto.cc crypto-utils-cyassl.cc crypto-utils-fallback.cc crypto-utils-openssl.cc crypto-utils-polarssl.cc + crypto-utils.cc + crypto.cc error.cc fdlimit.cc - file.cc file-posix.cc file-win32.cc + file.cc handshake.cc inout.cc log.cc @@ -36,46 +37,46 @@ set(PROJECT_FILES natpmp.cc net.cc peer-io.cc - peer-mgr.cc peer-mgr-active-requests.cc peer-mgr-wishlist.cc + peer-mgr.cc peer-msgs.cc - platform.cc platform-quota.cc + platform.cc port-forwarding.cc ptrarray.cc quark.cc resume.cc - rpcimpl.cc rpc-server.cc - session.cc + rpcimpl.cc session-id.cc + session.cc + stats.cc subprocess-posix.cc subprocess-win32.cc - stats.cc - torrent.cc torrent-ctor.cc torrent-magnet.cc - tr-dht.cc - trevent.cc + torrent.cc tr-assert.cc + tr-dht.cc tr-getopt.cc tr-lpd.cc tr-udp.cc tr-utp.cc + trevent.cc upnp.cc utils.cc variant-benc.cc - variant.cc variant-json.cc + variant.cc verify.cc - watchdir.cc watchdir-generic.cc watchdir-inotify.cc watchdir-kqueue.cc watchdir-win32.cc - web.cc + watchdir.cc web-utils.cc + web.cc webseed.cc ) @@ -147,6 +148,7 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS announcer.h bandwidth.h bitfield.h + block-info.h blocklist.h cache.h clients.h @@ -164,9 +166,9 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS net.h peer-common.h peer-io.h - peer-mgr.h peer-mgr-active-requests.h peer-mgr-wishlist.h + peer-mgr.h peer-msgs.h peer-socket.h platform-quota.h diff --git a/libtransmission/block-info.cc b/libtransmission/block-info.cc new file mode 100644 index 000000000..41f6f5978 --- /dev/null +++ b/libtransmission/block-info.cc @@ -0,0 +1,87 @@ +/* + * This file Copyright (C) 2007-2014 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + */ + +#include +#include + +#include + +#include "transmission.h" + +#include "block-info.h" + +// Decide on a block size. Constraints: +// (1) most clients decline requests over 16 KiB +// (2) pieceSize must be a multiple of block size +uint32_t tr_block_info::bestBlockSize(uint64_t piece_size) +{ + uint32_t b = piece_size; + + auto constexpr MaxBlockSize = uint32_t{ 1024 * 16 }; + while (b > MaxBlockSize) + { + b /= 2U; + } + + if (b == 0 || piece_size % b != 0) // not cleanly divisible + { + return 0; + } + + return b; +} + +void tr_block_info::initSizes(uint64_t total_size_in, uint64_t piece_size_in) +{ + total_size = total_size_in; + piece_size = piece_size_in; + block_size = bestBlockSize(piece_size); + + if (piece_size == 0 || block_size == 0) + { + return; + } + + n_pieces = (total_size + piece_size - 1) / piece_size; + + auto remainder = total_size % piece_size; + final_piece_size = remainder ? remainder : piece_size; + + remainder = total_size % block_size; + final_block_size = remainder ? remainder : block_size; + + if (block_size != 0) + { + n_blocks = (total_size + block_size - 1) / block_size; + n_blocks_in_piece = piece_size / block_size; + n_blocks_in_final_piece = (final_piece_size + block_size - 1) / block_size; + } + +#ifdef TR_ENABLE_ASSERTS + // check our work + if (block_size != 0) + { + TR_ASSERT(piece_size % block_size == 0); + } + + uint64_t t = n_pieces - 1; + t *= piece_size; + t += final_piece_size; + TR_ASSERT(t == total_size); + + t = n_blocks - 1; + t *= block_size; + t += final_block_size; + TR_ASSERT(t == total_size); + + t = n_pieces - 1; + t *= n_blocks_in_piece; + t += n_blocks_in_final_piece; + TR_ASSERT(t == n_blocks); +#endif +} diff --git a/libtransmission/block-info.h b/libtransmission/block-info.h new file mode 100644 index 000000000..60a82fadc --- /dev/null +++ b/libtransmission/block-info.h @@ -0,0 +1,93 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + */ + +#pragma once + +#ifndef __TRANSMISSION__ +#error only libtransmission should #include this header. +#endif + +#include "transmission.h" + +#include "metainfo.h" + +struct tr_block_info +{ + uint64_t total_size = 0; + uint64_t piece_size = 0; + uint64_t n_pieces = 0; + + tr_block_index_t n_blocks = 0; + tr_block_index_t n_blocks_in_piece = 0; + tr_block_index_t n_blocks_in_final_piece = 0; + uint32_t block_size = 0; + uint32_t final_block_size = 0; + uint32_t final_piece_size = 0; + + tr_block_info() = default; + tr_block_info(uint64_t total_size, uint64_t piece_size) + { + initSizes(total_size, piece_size); + } + + void initSizes(uint64_t total_size_in, uint64_t piece_size_in); + + constexpr tr_piece_index_t pieceForBlock(tr_block_index_t block) const + { + return n_blocks_in_piece ? block / n_blocks_in_piece : 0; + } + + constexpr uint32_t countBytesInPiece(tr_piece_index_t piece) const + { + // how many bytes are in this piece? + return piece + 1 == n_pieces ? final_piece_size : piece_size; + } + + constexpr uint32_t countBytesInBlock(tr_block_index_t block) const + { + // how many bytes are in this block? + return block + 1 == n_blocks ? final_block_size : block_size; + } + + constexpr tr_block_index_t blockOf(uint64_t offset) const + { + return offset / block_size; + } + + constexpr uint64_t offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + auto ret = piece_size; + ret *= piece; + ret += offset; + ret += length; + return ret; + } + + constexpr tr_block_index_t blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return blockOf(this->offset(piece, offset, length)); + } + + constexpr tr_block_range_t blockRangeForPiece(tr_piece_index_t piece) const + { + if (block_size == 0) + { + return {}; + } + + uint64_t offset = piece_size; + offset *= piece; + tr_block_index_t const first_block = offset / block_size; + offset += countBytesInPiece(piece) - 1; + tr_block_index_t const final_block = offset / block_size; + + return { first_block, final_block }; + } + + static uint32_t bestBlockSize(uint64_t piece_size); +}; diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc index 63495945b..43f4c972c 100644 --- a/libtransmission/cache.cc +++ b/libtransmission/cache.cc @@ -309,7 +309,7 @@ static struct cache_block* findBlock(tr_cache* cache, tr_torrent* torrent, tr_pi { struct cache_block key; key.tor = torrent; - key.block = _tr_block(torrent, piece, offset); + key.block = torrent->blockOf(piece, offset); return static_cast(tr_ptrArrayFindSorted(&cache->blocks, &key, cache_block_compare)); } @@ -332,7 +332,7 @@ int tr_cacheWriteBlock( cb->piece = piece; cb->offset = offset; cb->length = length; - cb->block = _tr_block(torrent, piece, offset); + cb->block = torrent->blockOf(piece, offset); cb->evbuf = evbuffer_new(); tr_ptrArrayInsertSorted(&cache->blocks, cb, cache_block_compare); } diff --git a/libtransmission/completion.cc b/libtransmission/completion.cc index fecb4eeb7..51d76bca0 100644 --- a/libtransmission/completion.cc +++ b/libtransmission/completion.cc @@ -29,7 +29,7 @@ static void tr_cpReset(tr_completion* cp) void tr_cpConstruct(tr_completion* cp, tr_torrent* tor) { cp->tor = tor; - cp->blockBitfield = new tr_bitfield(tor->blockCount); + cp->blockBitfield = new tr_bitfield(tor->n_blocks); tr_cpReset(cp); } @@ -42,12 +42,12 @@ void tr_cpBlockInit(tr_completion* cp, tr_bitfield const& b) // set sizeNow cp->sizeNow = cp->blockBitfield->count(); - TR_ASSERT(cp->sizeNow <= cp->tor->blockCount); - cp->sizeNow *= cp->tor->blockSize; + TR_ASSERT(cp->sizeNow <= cp->tor->n_blocks); + cp->sizeNow *= cp->tor->block_size; - if (b.test(cp->tor->blockCount - 1)) + if (b.test(cp->tor->n_blocks - 1)) { - cp->sizeNow -= (cp->tor->blockSize - cp->tor->lastBlockSize); + cp->sizeNow -= (cp->tor->block_size - cp->tor->final_block_size); } TR_ASSERT(cp->sizeNow <= cp->tor->info.totalSize); @@ -80,12 +80,12 @@ tr_completeness tr_cpGetStatus(tr_completion const* cp) void tr_cpPieceRem(tr_completion* cp, tr_piece_index_t piece) { tr_torrent const* tor = cp->tor; - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, piece); - for (tr_block_index_t i = first; i <= last; ++i) + auto const [first, last] = cp->tor->blockRangeForPiece(piece); + for (tr_block_index_t block = first; block <= last; ++block) { - if (tr_cpBlockIsComplete(cp, i)) + if (tr_cpBlockIsComplete(cp, block)) { - cp->sizeNow -= tr_torBlockCountBytes(tor, i); + cp->sizeNow -= tor->countBytesInBlock(block); } } @@ -96,7 +96,7 @@ void tr_cpPieceRem(tr_completion* cp, tr_piece_index_t piece) void tr_cpPieceAdd(tr_completion* cp, tr_piece_index_t piece) { - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, piece); + auto const [first, last] = cp->tor->blockRangeForPiece(piece); for (tr_block_index_t i = first; i <= last; ++i) { tr_cpBlockAdd(cp, i); @@ -109,10 +109,10 @@ void tr_cpBlockAdd(tr_completion* cp, tr_block_index_t block) if (!tr_cpBlockIsComplete(cp, block)) { - tr_piece_index_t const piece = tr_torBlockPiece(cp->tor, block); + tr_piece_index_t const piece = cp->tor->pieceForBlock(block); cp->blockBitfield->set(block); - cp->sizeNow += tr_torBlockCountBytes(tor, block); + cp->sizeNow += tor->countBytesInBlock(block); cp->haveValidIsDirty = true; cp->sizeWhenDoneIsDirty = cp->sizeWhenDoneIsDirty || tor->pieceIsDnd(piece); @@ -136,7 +136,7 @@ uint64_t tr_cpHaveValid(tr_completion const* ccp) { if (tr_cpPieceIsComplete(ccp, i)) { - size += tr_torPieceCountBytes(tor, i); + size += tor->countBytesInPiece(i); } } @@ -165,7 +165,7 @@ uint64_t tr_cpSizeWhenDone(tr_completion const* ccp) for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p) { uint64_t n = 0; - uint64_t const pieceSize = tr_torPieceCountBytes(tor, p); + uint64_t const pieceSize = tor->countBytesInPiece(p); if (!tor->pieceIsDnd(p)) { @@ -173,18 +173,17 @@ uint64_t tr_cpSizeWhenDone(tr_completion const* ccp) } else { - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, p); - + auto const [first, last] = cp->tor->blockRangeForPiece(p); n = cp->blockBitfield->count(first, last + 1); - n *= cp->tor->blockSize; + n *= cp->tor->block_size; - if (last == cp->tor->blockCount - 1 && cp->blockBitfield->test(last)) + if (last == cp->tor->n_blocks - 1 && cp->blockBitfield->test(last)) { - n -= cp->tor->blockSize - cp->tor->lastBlockSize; + n -= cp->tor->block_size - cp->tor->final_block_size; } } - TR_ASSERT(n <= tr_torPieceCountBytes(tor, p)); + TR_ASSERT(n <= tor->countBytesInPiece(p)); size += n; } } @@ -222,7 +221,7 @@ void tr_cpGetAmountDone(tr_completion const* cp, float* tab, int tabCount) else { tr_piece_index_t const piece = (tr_piece_index_t)i * interval; - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, piece); + auto const [first, last] = cp->tor->blockRangeForPiece(piece); tab[i] = cp->blockBitfield->count(first, last + 1) / (float)(last + 1 - first); } } @@ -235,7 +234,7 @@ size_t tr_cpMissingBlocksInPiece(tr_completion const* cp, tr_piece_index_t piece return 0; } - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, piece); + auto const [first, last] = cp->tor->blockRangeForPiece(piece); return (last + 1 - first) - cp->blockBitfield->count(first, last + 1); } @@ -246,8 +245,8 @@ size_t tr_cpMissingBytesInPiece(tr_completion const* cp, tr_piece_index_t piece) return 0; } - size_t const pieceByteSize = tr_torPieceCountBytes(cp->tor, piece); - auto const [first, last] = tr_torGetPieceBlockRange(cp->tor, piece); + size_t const pieceByteSize = cp->tor->countBytesInPiece(piece); + auto const [first, last] = cp->tor->blockRangeForPiece(piece); auto haveBytes = size_t{}; if (first != last) @@ -256,12 +255,12 @@ size_t tr_cpMissingBytesInPiece(tr_completion const* cp, tr_piece_index_t piece) It's faster to handle the last block separately because its size needs to be checked separately. */ haveBytes = cp->blockBitfield->count(first, last); - haveBytes *= cp->tor->blockSize; + haveBytes *= cp->tor->block_size; } if (cp->blockBitfield->test(last)) /* handle the last block */ { - haveBytes += tr_torBlockCountBytes(cp->tor, last); + haveBytes += cp->tor->countBytesInBlock(last); } TR_ASSERT(haveBytes <= pieceByteSize); diff --git a/libtransmission/inout.cc b/libtransmission/inout.cc index 1957210a4..081b733c5 100644 --- a/libtransmission/inout.cc +++ b/libtransmission/inout.cc @@ -260,12 +260,12 @@ static std::optional recalculateHash(tr_torrent* tor, tr_piece TR_ASSERT(tor != nullptr); TR_ASSERT(piece < tor->info.pieceCount); - auto bytes_left = size_t{ tr_torPieceCountBytes(tor, piece) }; + auto bytes_left = size_t{ tor->countBytesInPiece(piece) }; auto offset = uint32_t{}; tr_ioPrefetch(tor, piece, offset, bytes_left); auto sha = tr_sha1_init(); - auto buffer = std::vector(tor->blockSize); + auto buffer = std::vector(tor->block_size); while (bytes_left != 0) { size_t const len = std::min(bytes_left, std::size(buffer)); diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index f3fb818fc..61395e5cf 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -225,7 +225,7 @@ tr_peer::tr_peer(tr_torrent const* tor, peer_atom* atom_in) : session{ tor->session } , atom{ atom_in } , swarm{ tor->swarm } - , blame{ tor->blockCount } + , blame{ tor->n_blocks } , have{ tor->info.pieceCount } { } @@ -554,7 +554,7 @@ static void updateEndgame(tr_swarm* s) { /* we consider ourselves to be in endgame if the number of bytes we've got requested is >= the number of bytes left to download */ - s->endgame = uint64_t(std::size(s->active_requests)) * s->tor->blockSize >= tr_torrentGetLeftUntilDone(s->tor); + s->endgame = uint64_t(std::size(s->active_requests)) * s->tor->block_size >= tr_torrentGetLeftUntilDone(s->tor); } std::vector tr_peerMgrGetNextRequests(tr_torrent* torrent, tr_peer* peer, size_t numwant) @@ -596,7 +596,7 @@ std::vector tr_peerMgrGetNextRequests(tr_torrent* torrent, tr_ tr_block_range_t blockRange(tr_piece_index_t piece) const override { - return tr_torGetPieceBlockRange(torrent_, piece); + return torrent_->blockRangeForPiece(piece); } tr_piece_index_t countAllPieces() const override @@ -725,14 +725,14 @@ static void peerSuggestedPiece(tr_swarm* /*s*/, tr_peer* /*peer*/, tr_piece_inde /* request the blocks that we don't have in this piece */ { tr_torrent const* tor = t->tor; - auto const [first, last] = tr_torGetPieceBlockRange(t->tor, pieceIndex); + auto const [first, last] = tor->blockRangeForPiece(pieceIndex); for (tr_block_index_t b = first; b <= last; ++b) { if (tr_torrentBlockIsComplete(tor, b)) { uint32_t const offset = getBlockOffsetInPiece(tor, b); - uint32_t const length = tr_torBlockCountBytes(tor, b); + uint32_t const length = tor->countBytesInBlock(b); tr_peerMsgsAddRequest(peer->msgs, pieceIndex, offset, length); incrementPieceRequests(t, pieceIndex); } @@ -762,7 +762,7 @@ void tr_peerMgrPieceCompleted(tr_torrent* tor, tr_piece_index_t p) if (pieceCameFromPeers) /* webseed downloads don't belong in announce totals */ { - tr_announcerAddBytes(tor, TR_ANN_DOWN, tr_torPieceCountBytes(tor, p)); + tr_announcerAddBytes(tor, TR_ANN_DOWN, tor->countBytesInPiece(p)); } /* bookkeeping */ @@ -824,7 +824,7 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs) break; case TR_PEER_CLIENT_GOT_REJ: - s->active_requests.remove(_tr_block(s->tor, e->pieceIndex, e->offset), peer); + s->active_requests.remove(s->tor->blockOf(e->pieceIndex, e->offset), peer); break; case TR_PEER_CLIENT_GOT_CHOKE: @@ -851,7 +851,7 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs) { tr_torrent* tor = s->tor; tr_piece_index_t const p = e->pieceIndex; - tr_block_index_t const block = _tr_block(tor, p, e->offset); + tr_block_index_t const block = tor->blockOf(p, e->offset); cancelAllRequestsForBlock(s, block, peer); peer->blocksSentToClient.add(tr_time(), 1); tr_torrentGotBlock(tor, block); @@ -1243,7 +1243,7 @@ tr_pex* tr_peerMgrCompact6ToPex( void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t pieceIndex) { tr_swarm* s = tor->swarm; - uint32_t const byteCount = tr_torPieceCountBytes(tor, pieceIndex); + uint32_t const byteCount = tor->countBytesInPiece(pieceIndex); for (int i = 0, n = tr_ptrArraySize(&s->peers); i != n; ++i) { diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 149eb9ba2..81b7afb94 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -358,7 +358,7 @@ public: bool is_reading_block(tr_block_index_t block) const override { - return state == AwaitingBtPiece && block == _tr_block(torrent, incoming.blockReq.index, incoming.blockReq.offset); + return state == AwaitingBtPiece && block == torrent->blockOf(incoming.blockReq.index, incoming.blockReq.offset); } void cancel_block_request(tr_block_index_t block) override @@ -1885,7 +1885,7 @@ static int clientGotBlock(tr_peerMsgsImpl* msgs, struct evbuffer* data, struct p TR_ASSERT(req != nullptr); tr_torrent* tor = msgs->torrent; - tr_block_index_t const block = _tr_block(tor, req->index, req->offset); + tr_block_index_t const block = tor->blockOf(req->index, req->offset); if (!requestIsValid(msgs, req)) { @@ -1893,9 +1893,9 @@ static int clientGotBlock(tr_peerMsgsImpl* msgs, struct evbuffer* data, struct p return EBADMSG; } - if (req->length != tr_torBlockCountBytes(msgs->torrent, block)) + if (req->length != msgs->torrent->countBytesInBlock(block)) { - dbgmsg(msgs, "wrong block size -- expected %u, got %d", tr_torBlockCountBytes(msgs->torrent, block), req->length); + dbgmsg(msgs, "wrong block size -- expected %u, got %d", msgs->torrent->countBytesInBlock(block), req->length); return EMSGSIZE; } @@ -2027,7 +2027,7 @@ static void updateDesiredRequestCount(tr_peerMsgsImpl* msgs) * many requests we should send to this peer */ size_t constexpr Floor = 32; size_t constexpr Seconds = RequestBufSecs; - size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / torrent->blockSize; + size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / torrent->block_size; size_t const ceil = msgs->reqq ? *msgs->reqq : 250; msgs->desired_request_count = std::clamp(estimated_blocks_in_period, Floor, ceil); } @@ -2194,7 +2194,7 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now) *** Data Blocks **/ - if (tr_peerIoGetWriteBufferSpace(msgs->io, now) >= msgs->torrent->blockSize && popNextRequest(msgs, &req)) + if (tr_peerIoGetWriteBufferSpace(msgs->io, now) >= msgs->torrent->block_size && popNextRequest(msgs, &req)) { --msgs->prefetchCount; diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index afc341ae2..6055ed142 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -615,7 +615,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor) /// COMPLETION - auto blocks = tr_bitfield{ tor->blockCount }; + auto blocks = tr_bitfield{ tor->n_blocks }; char const* err = nullptr; auto sv = std::string_view{}; tr_variant const* const b = tr_variantDictFind(prog, TR_KEY_blocks); diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 2ad96c3dc..ebeca4789 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -721,63 +721,10 @@ uint32_t tr_getBlockSize(uint32_t pieceSize) return b; } -static void refreshCurrentDir(tr_torrent* tor); - static void torrentInitFromInfo(tr_torrent* tor) { - tr_info const* const info = &tor->info; - - tor->blockSize = tr_getBlockSize(info->pieceSize); - - if (info->pieceSize != 0) - { - tor->lastPieceSize = (uint32_t)(info->totalSize % info->pieceSize); - } - - if (tor->lastPieceSize == 0) - { - tor->lastPieceSize = info->pieceSize; - } - - if (tor->blockSize != 0) - { - tor->lastBlockSize = info->totalSize % tor->blockSize; - } - - if (tor->lastBlockSize == 0) - { - tor->lastBlockSize = tor->blockSize; - } - - tor->blockCount = tor->blockSize != 0 ? (info->totalSize + tor->blockSize - 1) / tor->blockSize : 0; - tor->blockCountInPiece = tor->blockSize != 0 ? info->pieceSize / tor->blockSize : 0; - tor->blockCountInLastPiece = tor->blockSize != 0 ? (tor->lastPieceSize + tor->blockSize - 1) / tor->blockSize : 0; - -#ifdef TR_ENABLE_ASSERTS - /* check our work */ - if (tor->blockSize != 0) - { - TR_ASSERT(info->pieceSize % tor->blockSize == 0); - } - - uint64_t t = info->pieceCount - 1; - t *= info->pieceSize; - t += tor->lastPieceSize; - TR_ASSERT(t == info->totalSize); - - t = tor->blockCount - 1; - t *= tor->blockSize; - t += tor->lastBlockSize; - TR_ASSERT(t == info->totalSize); - - t = info->pieceCount - 1; - t *= tor->blockCountInPiece; - t += tor->blockCountInLastPiece; - TR_ASSERT(t == (uint64_t)tor->blockCount); -#endif - + tor->initSizes(tor->info.totalSize, tor->info.pieceSize); tr_cpConstruct(&tor->completion, tor); - tr_torrentInitFilePieces(tor); } @@ -836,6 +783,8 @@ static void callScriptIfEnabled(tr_torrent const* tor, TrScript type) } } +static void refreshCurrentDir(tr_torrent* tor); + static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) { auto const lock = tor->unique_lock(); @@ -1374,21 +1323,21 @@ static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t i // the first block if (tr_torrentBlockIsComplete(tor, first)) { - total += tor->blockSize - f.offset % tor->blockSize; + total += tor->block_size - f.offset % tor->block_size; } // the middle blocks if (first + 1 < last) { uint64_t u = tor->completion.blockBitfield->count(first + 1, last); - u *= tor->blockSize; + u *= tor->block_size; total += u; } // the last block if (tr_torrentBlockIsComplete(tor, last)) { - total += f.offset + f.length - (uint64_t)tor->blockSize * last; + total += f.offset + f.length - (uint64_t)tor->block_size * last; } return total; @@ -2372,33 +2321,12 @@ void tr_torrentGetBlockLocation( uint32_t* length) { uint64_t pos = block; - pos *= tor->blockSize; + pos *= tor->block_size; *piece = pos / tor->info.pieceSize; uint64_t piece_begin = tor->info.pieceSize; piece_begin *= *piece; *offset = pos - piece_begin; - *length = tr_torBlockCountBytes(tor, block); -} - -tr_block_index_t _tr_block(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset) -{ - TR_ASSERT(tr_isTorrent(tor)); - - tr_block_index_t ret = 0; - - if (tor->blockSize > 0) - { - ret = index; - ret *= tor->info.pieceSize / tor->blockSize; - ret += offset / tor->blockSize; - } - else - { - tr_logAddTorErr(tor, "Cannot calculate block number when blockSize is zero"); - TR_ASSERT(tor->blockSize > 0); - } - - return ret; + *length = tor->countBytesInBlock(block); } bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset, uint32_t length) @@ -2415,7 +2343,7 @@ bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_ { err = 2; } - else if (offset + length > tr_torPieceCountBytes(tor, index)) + else if (offset + length > tor->countBytesInPiece(index)) { err = 3; } @@ -2459,25 +2387,14 @@ tr_block_range_t tr_torGetFileBlockRange(tr_torrent const* tor, tr_file_index_t tr_file const* f = &tor->info.files[file]; uint64_t offset = f->offset; - tr_block_index_t const first = offset / tor->blockSize; + tr_block_index_t const first = offset / tor->block_size; if (f->length == 0) { return { first, first }; } offset += f->length - 1; - tr_block_index_t const last = offset / tor->blockSize; - return { first, last }; -} - -tr_block_range_t tr_torGetPieceBlockRange(tr_torrent const* tor, tr_piece_index_t const piece) -{ - uint64_t offset = tor->info.pieceSize; - offset *= piece; - tr_block_index_t const first = offset / tor->blockSize; - offset += tr_torPieceCountBytes(tor, piece) - 1; - tr_block_index_t const last = offset / tor->blockSize; - + tr_block_index_t const last = offset / tor->block_size; return { first, last }; } @@ -3159,7 +3076,7 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block) tr_cpBlockAdd(&tor->completion, block); tr_torrentSetDirty(tor); - tr_piece_index_t const p = tr_torBlockPiece(tor, block); + tr_piece_index_t const p = tor->pieceForBlock(block); if (tr_torrentPieceIsComplete(tor, p)) { @@ -3169,7 +3086,7 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block) } else { - uint32_t const n = tr_torPieceCountBytes(tor, p); + uint32_t const n = tor->countBytesInPiece(p); tr_logAddTorErr(tor, _("Piece %" PRIu32 ", which was just downloaded, failed its checksum test"), p); tor->corruptCur += n; tor->downloadedCur -= std::min(tor->downloadedCur, uint64_t{ n }); @@ -3179,7 +3096,7 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block) } else { - uint32_t const n = tr_torBlockCountBytes(tor, block); + uint32_t const n = tor->countBytesInBlock(block); tor->downloadedCur -= std::min(tor->downloadedCur, uint64_t{ n }); tr_logAddTorDbg(tor, "we have this block already..."); } diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 108380b6f..3b87e7762 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -19,8 +19,11 @@ #include #include +#include "transmission.h" + #include "bandwidth.h" #include "bitfield.h" +#include "block-info.h" #include "completion.h" #include "file.h" #include "quark.h" @@ -76,10 +79,6 @@ tr_torrent* tr_torrentFindFromObfuscatedHash(tr_session* session, uint8_t const* bool tr_torrentIsPieceTransferAllowed(tr_torrent const* torrent, tr_direction direction); -#define tr_block(a, b) _tr_block(tor, a, b) - -tr_block_index_t _tr_block(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset); - bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset, uint32_t length); uint64_t tr_pieceOffset(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset, uint32_t length); @@ -93,8 +92,6 @@ void tr_torrentGetBlockLocation( tr_block_range_t tr_torGetFileBlockRange(tr_torrent const* tor, tr_file_index_t const file); -tr_block_range_t tr_torGetPieceBlockRange(tr_torrent const* tor, tr_piece_index_t const piece); - void tr_torrentInitFilePriority(tr_torrent* tor, tr_file_index_t fileIndex, tr_priority_t priority); void tr_torrentCheckSeedLimit(tr_torrent* tor); @@ -128,7 +125,7 @@ tr_torrent_activity tr_torrentGetActivity(tr_torrent const* tor); struct tr_incomplete_metadata; /** @brief Torrent object */ -struct tr_torrent +struct tr_torrent : public tr_block_info { public: void setLocation( @@ -320,16 +317,6 @@ public: * This pointer will be equal to downloadDir or incompleteDir */ char const* currentDir; - /* How many bytes we ask for per request */ - uint32_t blockSize; - tr_block_index_t blockCount; - - uint32_t lastBlockSize; - uint32_t lastPieceSize; - - uint32_t blockCountInPiece; - uint32_t blockCountInLastPiece; - struct tr_completion completion; tr_completeness completeness; @@ -428,24 +415,6 @@ private: mutable std::vector piece_checksums_; }; -/* what piece index is this block in? */ -constexpr tr_piece_index_t tr_torBlockPiece(tr_torrent const* tor, tr_block_index_t const block) -{ - return block / tor->blockCountInPiece; -} - -/* how many bytes are in this piece? */ -constexpr uint32_t tr_torPieceCountBytes(tr_torrent const* tor, tr_piece_index_t const piece) -{ - return piece + 1 == tor->info.pieceCount ? tor->lastPieceSize : tor->info.pieceSize; -} - -/* how many bytes are in this block? */ -constexpr uint32_t tr_torBlockCountBytes(tr_torrent const* tor, tr_block_index_t const block) -{ - return block + 1 == tor->blockCount ? tor->lastBlockSize : tor->blockSize; -} - static inline bool tr_torrentExists(tr_session const* session, uint8_t const* torrentHash) { return tr_torrentFindFromHash((tr_session*)session, torrentHash) != nullptr; diff --git a/libtransmission/verify.cc b/libtransmission/verify.cc index ad7a6a802..45e9de69f 100644 --- a/libtransmission/verify.cc +++ b/libtransmission/verify.cc @@ -70,7 +70,7 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) } /* figure out how much we can read this pass */ - uint64_t leftInPiece = tr_torPieceCountBytes(tor, pieceIndex) - piecePos; + uint64_t leftInPiece = tor->countBytesInPiece(pieceIndex) - piecePos; uint64_t leftInFile = file->length - filePos; uint64_t bytesThisPass = std::min(leftInFile, leftInPiece); bytesThisPass = std::min(bytesThisPass, uint64_t{ buflen }); diff --git a/libtransmission/webseed.cc b/libtransmission/webseed.cc index f0ae089a8..853c3c2a1 100644 --- a/libtransmission/webseed.cc +++ b/libtransmission/webseed.cc @@ -147,7 +147,7 @@ static void fire_client_got_rejs(tr_torrent* tor, tr_webseed* w, tr_block_index_ { if (i == count) { - e.length = tr_torBlockCountBytes(tor, block + count - 1); + e.length = tor->countBytesInBlock(block + count - 1); } publish(w, &e); @@ -165,7 +165,7 @@ static void fire_client_got_blocks(tr_torrent* tor, tr_webseed* w, tr_block_inde { if (i == count) { - e.length = tr_torBlockCountBytes(tor, block + count - 1); + e.length = tor->countBytesInBlock(block + count - 1); } publish(w, &e); @@ -206,7 +206,7 @@ static void write_block_func(void* vdata) auto* const tor = tr_torrentFindFromId(data->session, data->torrent_id); if (tor != nullptr) { - uint32_t const block_size = tor->blockSize; + uint32_t const block_size = tor->block_size; uint32_t len = evbuffer_get_length(buf); uint32_t const offset_end = data->block_offset + len; tr_cache* cache = data->session->cache; @@ -371,12 +371,12 @@ static void on_idle(tr_webseed* w) task->session = tor->session; task->webseed = w; task->block = first; - task->piece_index = tr_torBlockPiece(tor, first); - task->piece_offset = tor->blockSize * first - tor->info.pieceSize * task->piece_index; - task->length = (last - first) * tor->blockSize + tr_torBlockCountBytes(tor, last); + task->piece_index = tor->pieceForBlock(first); + task->piece_offset = tor->block_size * first - tor->info.pieceSize * task->piece_index; + task->length = (last - first) * tor->block_size + tor->countBytesInBlock(last); task->blocks_done = 0; task->response_code = 0; - task->block_size = tor->blockSize; + task->block_size = tor->block_size; task->content = evbuffer_new(); evbuffer_add_cb(task->content, on_content_changed, task); w->tasks.insert(task); @@ -425,7 +425,7 @@ static void web_response_func( if (!success) { - tr_block_index_t const blocks_remain = (t->length + tor->blockSize - 1) / tor->blockSize - t->blocks_done; + tr_block_index_t const blocks_remain = (t->length + tor->block_size - 1) / tor->block_size - t->blocks_done; if (blocks_remain != 0) { @@ -448,7 +448,7 @@ static void web_response_func( } else { - uint32_t const bytes_done = t->blocks_done * tor->blockSize; + uint32_t const bytes_done = t->blocks_done * tor->block_size; uint32_t const buf_len = evbuffer_get_length(t->content); if (bytes_done + buf_len < t->length) @@ -508,7 +508,7 @@ static void task_request_next_chunk(struct tr_webseed_task* t) auto& urls = t->webseed->file_urls; tr_info const* inf = tr_torrentInfo(tor); - uint64_t const remain = t->length - t->blocks_done * tor->blockSize - evbuffer_get_length(t->content); + uint64_t const remain = t->length - t->blocks_done * tor->block_size - evbuffer_get_length(t->content); uint64_t const total_offset = tr_pieceOffset(tor, t->piece_index, t->piece_offset, t->length - remain); tr_piece_index_t const step_piece = total_offset / inf->pieceSize; diff --git a/tests/libtransmission/CMakeLists.txt b/tests/libtransmission/CMakeLists.txt index d1f10dfc4..257187910 100644 --- a/tests/libtransmission/CMakeLists.txt +++ b/tests/libtransmission/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(libtransmission-test bitfield-test.cc + block-info-test.cc blocklist-test.cc clients-test.cc copy-test.cc @@ -14,9 +15,9 @@ add_executable(libtransmission-test makemeta-test.cc metainfo-test.cc move-test.cc - peer-msgs-test.cc - peer-mgr-wishlist-test.cc peer-mgr-active-requests-test.cc + peer-mgr-wishlist-test.cc + peer-msgs-test.cc quark-test.cc rename-test.cc rpc-test.cc diff --git a/tests/libtransmission/block-info-test.cc b/tests/libtransmission/block-info-test.cc new file mode 100644 index 000000000..05bcff342 --- /dev/null +++ b/tests/libtransmission/block-info-test.cc @@ -0,0 +1,150 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + */ + +#include + +#include "transmission.h" + +#include "block-info.h" + +#include "gtest/gtest.h" + +using BlockInfoTest = ::testing::Test; + +TEST_F(BlockInfoTest, fieldsAreSet) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 4; + uint64_t constexpr TotalSize = PieceSize * PieceCount; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(ExpectedBlockSize, info.block_size); + EXPECT_EQ(ExpectedBlockSize, info.final_block_size); + EXPECT_EQ(ExpectedBlocksPerPiece, info.n_blocks_in_final_piece); + EXPECT_EQ(ExpectedBlocksPerPiece, info.n_blocks_in_piece); + EXPECT_EQ(PieceCount, info.n_pieces); + EXPECT_EQ(PieceSize, info.final_piece_size); + EXPECT_EQ(PieceSize, info.piece_size); + EXPECT_EQ(TotalSize, info.total_size); +} + +TEST_F(BlockInfoTest, handlesOddSize) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(1, info.final_block_size); + EXPECT_EQ(1, info.final_piece_size); + EXPECT_EQ(1, info.n_blocks_in_final_piece); + EXPECT_EQ(ExpectedBlockSize, info.block_size); + EXPECT_EQ(ExpectedBlocksPerPiece, info.n_blocks_in_piece); + EXPECT_EQ(PieceCount, info.n_pieces); + EXPECT_EQ(PieceSize, info.piece_size); + EXPECT_EQ(TotalSize, info.total_size); +} + +TEST_F(BlockInfoTest, pieceForBlock) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 4; + uint64_t constexpr TotalSize = PieceSize * PieceCount; + info.initSizes(TotalSize, PieceSize); + + for (uint64_t i = 0; i < info.n_blocks; ++i) + { + EXPECT_EQ((i * ExpectedBlockSize) / PieceSize, info.pieceForBlock(i)); + } +} + +TEST_F(BlockInfoTest, countBytesInPiece) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(PieceSize, info.countBytesInPiece(info.n_pieces - 2)); + EXPECT_EQ(1, info.countBytesInPiece(info.n_pieces - 1)); +} + +TEST_F(BlockInfoTest, countBytesInBlock) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(ExpectedBlockSize, info.countBytesInBlock(info.n_blocks - 2)); + EXPECT_EQ(1, info.countBytesInBlock(info.n_blocks - 1)); +} + +TEST_F(BlockInfoTest, offset) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(0, info.offset(0, 0)); + EXPECT_EQ(1, info.offset(0, 0, 1)); + EXPECT_EQ(PieceSize * 2 + 100 + 1, info.offset(2, 100, 1)); + EXPECT_EQ( + info.total_size - 1, + info.offset( + info.n_pieces - 1, + ((info.n_blocks_in_final_piece - 1) * info.block_size) + info.n_blocks_in_final_piece - 1)); + EXPECT_EQ(info.n_blocks_in_piece, info.blockOf(info.offset(1, 0))); + EXPECT_EQ(info.n_blocks_in_piece, info.blockOf(info.offset(1, info.block_size - 1))); + EXPECT_EQ(info.n_blocks_in_piece + 1, info.blockOf(info.offset(1, info.block_size))); + EXPECT_EQ(info.n_blocks - 1, info.blockOf(info.total_size - 1)); +} + +TEST_F(BlockInfoTest, blockRangeForPiece) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + EXPECT_EQ(0, info.blockRangeForPiece(0).first); + EXPECT_EQ(3, info.blockRangeForPiece(0).last); + EXPECT_EQ(12, info.blockRangeForPiece(3).first); + EXPECT_EQ(15, info.blockRangeForPiece(3).last); + EXPECT_EQ(16, info.blockRangeForPiece(4).first); + EXPECT_EQ(16, info.blockRangeForPiece(4).last); +} diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc index 265a78abf..b56774e97 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -80,28 +80,28 @@ TEST_P(IncompleteDirTest, incompleteDir) auto const test_incomplete_dir_threadfunc = [](void* vdata) noexcept { auto* data = static_cast(vdata); - tr_cacheWriteBlock(data->session->cache, data->tor, 0, data->offset, data->tor->blockSize, data->buf); + tr_cacheWriteBlock(data->session->cache, data->tor, 0, data->offset, data->tor->block_size, data->buf); tr_torrentGotBlock(data->tor, data->block); data->done = true; }; // now finish writing it { - char* zero_block = tr_new0(char, tor->blockSize); + char* zero_block = tr_new0(char, tor->block_size); struct TestIncompleteDirData data = {}; data.session = session_; data.tor = tor; data.buf = evbuffer_new(); - auto const [first, last] = tr_torGetPieceBlockRange(tor, data.pieceIndex); + auto const [first, last] = tor->blockRangeForPiece(data.pieceIndex); for (tr_block_index_t block_index = first; block_index <= last; ++block_index) { - evbuffer_add(data.buf, zero_block, tor->blockSize); + evbuffer_add(data.buf, zero_block, tor->block_size); data.block = block_index; data.done = false; - data.offset = data.block * tor->blockSize; + data.offset = data.block * tor->block_size; tr_runInEventThread(session_, test_incomplete_dir_threadfunc, &data); auto const test = [&data]()