Excuse the sprawl. Much of this didn't fit into self-contained commits.
return success;
}
+tr_bool
+tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len )
+{
+ const tr_bool success = tr_bencIsString( val );
+
+ if( success ) {
+ *setme_raw = (uint8_t*) getStr(val);
+ *setme_len = val->val.s.len;
+ }
+
+ return success;
+}
+
tr_bool
tr_bencGetBool( const tr_benc * val, tr_bool * setme )
{
}
tr_bool
-tr_bencDictFindRaw( tr_benc * dict,
- const char * key,
- const uint8_t ** setme_raw,
- size_t * setme_len )
+tr_bencDictFindRaw( tr_benc * dict, const char * key, const uint8_t ** setme_raw, size_t * setme_len )
{
- tr_benc * child;
- const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
-
- if( found ) {
- *setme_raw = (uint8_t*) getStr(child);
- *setme_len = child->val.s.len;
- }
-
- return found;
+ return tr_bencGetRaw( tr_bencDictFind( dict, key ), setme_raw, setme_len );
}
/***
}
else
{
- tr_fsync( fd );
+ //tr_fsync( fd );
tr_close_file( fd );
#ifdef WIN32
@return TRUE if successful, or FALSE if the variant could not be represented as a string */
tr_bool tr_bencGetStr( const tr_benc * val, const char ** setme );
+/** @brief Get a raw byte array from a variant object
+ @return TRUE if successful, or FALSE if the variant could not be represented as a raw byte array */
+tr_bool tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len );
+
/** @brief Get a boolean from a variant object
@return TRUE if successful, or FALSE if the variant could not be represented as a boolean */
tr_bool tr_bencGetBool( const tr_benc * val, tr_bool * setme );
#include "transmission.h"
#include "bitfield.h"
#include "bitset.h"
+#include "utils.h" /* tr_new0() */
+
+const tr_bitfield TR_BITFIELD_INIT = { NULL, 0, 0 };
tr_bitfield*
tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
}
tr_bitfield*
-tr_bitfieldDup( const tr_bitfield * in )
+tr_bitfieldNew( size_t bitCount )
{
- tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
+ return tr_bitfieldConstruct( tr_new( tr_bitfield, 1 ), bitCount );
+}
- ret->bitCount = in->bitCount;
- ret->byteCount = in->byteCount;
- ret->bits = tr_memdup( in->bits, in->byteCount );
- return ret;
+void
+tr_bitfieldFree( tr_bitfield * b )
+{
+ tr_free( tr_bitfieldDestruct( b ) );
}
void
return a;
}
+static const int trueBitCount[256] =
+{
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
size_t
tr_bitfieldCountTrueBits( const tr_bitfield* b )
{
size_t ret = 0;
const uint8_t * it, *end;
- static const int trueBitCount[256] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
- };
if( !b )
return 0;
return ret;
}
+
+size_t
+tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end )
+{
+ size_t ret = 0;
+ const int first_byte = begin >> 3u;
+ const int last_byte = ( end - 1 ) >> 3u;
+
+ assert( begin < end );
+
+ if( first_byte == last_byte )
+ {
+ int i;
+ uint8_t val = b->bits[first_byte];
+
+ i = begin - (first_byte * 8);
+ val <<= i;
+ val >>= i;
+ i = (last_byte+1)*8 - end;
+ val >>= i;
+ val <<= i;
+
+ ret += trueBitCount[val];
+ }
+ else
+ {
+ int i;
+ uint8_t val;
+
+ /* first byte */
+ i = begin - (first_byte * 8);
+ val = b->bits[first_byte];
+ val <<= i;
+ val >>= i;
+ ret += trueBitCount[val];
+
+ /* middle bytes */
+ for( i=first_byte+1; i<last_byte; ++i )
+ ret += trueBitCount[b->bits[i]];
+
+ /* last byte */
+ i = (last_byte+1)*8 - end;
+ val = b->bits[last_byte];
+ val >>= i;
+ val <<= i;
+ ret += trueBitCount[val];
+ }
+
+ assert( ret <= ( begin - end ) );
+ return ret;
+}
#define TR_BITFIELD_H 1
#include "transmission.h"
-#include "utils.h" /* tr_new0 */
/** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
typedef struct tr_bitfield
}
tr_bitfield;
-tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitcount );
+extern const tr_bitfield TR_BITFIELD_INIT;
-tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
+tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitCount );
-static inline tr_bitfield* tr_bitfieldNew( size_t bitcount )
-{
- return tr_bitfieldConstruct( tr_new0( tr_bitfield, 1 ), bitcount );
-}
+tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
-static inline void tr_bitfieldFree( tr_bitfield * b )
-{
- tr_free( tr_bitfieldDestruct( b ) );
-}
+tr_bitfield* tr_bitfieldNew( size_t bitCount );
-tr_bitfield* tr_bitfieldDup( const tr_bitfield* ) TR_GNUC_MALLOC;
+void tr_bitfieldFree( tr_bitfield * b );
void tr_bitfieldClear( tr_bitfield* );
size_t tr_bitfieldCountTrueBits( const tr_bitfield* );
+size_t tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end );
+
+
tr_bitfield* tr_bitfieldOr( tr_bitfield*, const tr_bitfield* );
/** A stripped-down version of bitfieldHas to be used
*/
#include "transmission.h"
+#include "bencode.h"
#include "bitset.h"
+#include "utils.h"
+
+const tr_bitset TR_BITSET_INIT = { FALSE, FALSE, { NULL, 0, 0 } };
+
+void
+tr_bitsetConstruct( tr_bitset * b, size_t bitCount )
+{
+ *b = TR_BITSET_INIT;
+ b->bitfield.bitCount = bitCount;
+}
void
-tr_bitsetConstructor( tr_bitset * b, size_t size )
+tr_bitsetDestruct( tr_bitset * b )
{
- tr_bitfieldConstruct( &b->bitfield, size );
+ tr_free( b->bitfield.bits );
+ *b = TR_BITSET_INIT;
+}
+
+static void
+tr_bitsetClear( tr_bitset * b )
+{
+ tr_free( b->bitfield.bits );
+ b->bitfield.bits = NULL;
+ b->haveAll = FALSE;
+ b->haveNone = FALSE;
}
void
-tr_bitsetDestructor( tr_bitset * b )
+tr_bitsetSetHaveAll( tr_bitset * b )
{
- tr_bitfieldDestruct( &b->bitfield );
+ tr_bitsetClear( b );
+ b->haveAll = TRUE;
+}
+
+void
+tr_bitsetSetHaveNone( tr_bitset * b )
+{
+ tr_bitsetClear( b );
+ b->haveNone = TRUE;
+}
+
+void
+tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield )
+{
+ const size_t n = tr_bitfieldCountTrueBits( bitfield );
+
+ if( n == 0 )
+ {
+ tr_bitsetSetHaveNone( b );
+ }
+ else if( n == bitfield->bitCount )
+ {
+ tr_bitsetSetHaveAll( b );
+ }
+ else
+ {
+ tr_bitsetDestruct( b );
+ b->bitfield.bits = tr_memdup( bitfield->bits, bitfield->byteCount );
+ b->bitfield.bitCount = bitfield->bitCount;
+ b->bitfield.byteCount = bitfield->byteCount;
+ }
}
+/***
+****
+***/
+
void
-tr_bitsetReserve( tr_bitset * b, size_t size )
+tr_bitsetAdd( tr_bitset * b, size_t i )
{
- if( b->bitfield.bitCount < size )
+ tr_bitfield * bf = &b->bitfield;
+
+ if( b->haveAll )
+ return;
+
+ b->haveNone = FALSE;
+
+ /* do we need to resize the bitfield to accomodate this bit? */
+ if( !bf->bits || ( bf->bitCount < i+1 ) )
{
- tr_bitfield * tmp = tr_bitfieldDup( &b->bitfield );
+ const size_t oldByteCount = bf->byteCount;
+ if( bf->bitCount < i + 1 )
+ bf->bitCount = i + 1;
+ bf->byteCount = ( bf->bitCount + 7u ) / 8u;
+ bf->bits = tr_renew( uint8_t, bf->bits, bf->byteCount );
+ if( bf->byteCount > oldByteCount )
+ memset( bf->bits + oldByteCount, 0, bf->byteCount - oldByteCount );
+ }
- tr_bitfieldDestruct( &b->bitfield );
- tr_bitfieldConstruct( &b->bitfield, size );
+ tr_bitfieldAdd( bf, i );
+}
- if( ( tmp->bits != NULL ) && ( tmp->byteCount > 0 ) )
- memcpy( b->bitfield.bits, tmp->bits, tmp->byteCount );
+void
+tr_bitsetRem( tr_bitset * b, size_t i )
+{
+ if( b->haveNone )
+ return;
+
+ b->haveAll = FALSE;
- tr_bitfieldFree( tmp );
+ if( !b->bitfield.bits )
+ {
+ tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
+ tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
}
+
+ tr_bitfieldRem( &b->bitfield, i );
}
+void
+tr_bitsetRemRange( tr_bitset * b, size_t begin, size_t end )
+{
+ if( b->haveNone )
+ return;
+
+ b->haveAll = FALSE;
+ if( !b->bitfield.bits )
+ {
+ tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
+ tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
+ }
+
+ tr_bitfieldRemRange( &b->bitfield, begin, end );
+}
+
+/***
+****
+***/
+
tr_bool
tr_bitsetHas( const tr_bitset * b, const size_t nth )
{
return tr_bitfieldHas( &b->bitfield, nth );
}
-void
-tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
+size_t
+tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end )
{
- if( b->haveAll )
- tr_bitfieldAddRange( a, 0, a->bitCount );
- else if( !b->haveNone )
- tr_bitfieldOr( a, &b->bitfield );
+ if( b->haveAll ) return end - begin;
+ if( b->haveNone ) return 0;
+ return tr_bitfieldCountRange( &b->bitfield, begin, end );
}
double
}
void
-tr_bitsetSetHaveAll( tr_bitset * b )
+tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
{
- b->haveAll = 1;
- b->haveNone = 0;
+ if( b->haveAll )
+ tr_bitfieldAddRange( a, 0, a->bitCount );
+ else if( !b->haveNone )
+ tr_bitfieldOr( a, &b->bitfield );
}
-void
-tr_bitsetSetHaveNone( tr_bitset * b )
+/***
+****
+***/
+
+tr_bool
+tr_bitsetFromBenc( tr_bitset * bitset, tr_benc * benc )
{
- b->haveAll = 0;
- b->haveNone = 1;
+ size_t buflen;
+ const uint8_t * buf;
+ tr_bool handled = FALSE;
+
+ if( tr_bencGetRaw( benc, &buf, &buflen ) )
+ {
+ if( ( buflen == 3 ) && !memcmp( buf, "all", 3 ) )
+ {
+ tr_bitsetSetHaveAll( bitset );
+ handled = TRUE;
+ }
+ else if( ( buflen == 4 ) && !memcmp( buf, "none", 4 ) )
+ {
+ tr_bitsetSetHaveNone( bitset );
+ handled = TRUE;
+ }
+ else
+ {
+ bitset->haveAll = FALSE;
+ bitset->haveNone = FALSE;
+ tr_free( bitset->bitfield.bits );
+ bitset->bitfield.bits = tr_memdup( buf, buflen );
+ bitset->bitfield.byteCount = buflen;
+ bitset->bitfield.bitCount = buflen * 8;
+ handled = TRUE;
+ }
+ }
+
+ return handled;
}
-int
-tr_bitsetAdd( tr_bitset * b, size_t i )
+void
+tr_bitsetToBenc( const tr_bitset * bitset, tr_benc * benc )
{
- int ret = 0;
- if( !b->haveAll ) {
- b->haveNone = 0;
- tr_bitsetReserve( b, i+1 );
- ret = tr_bitfieldAdd( &b->bitfield, i );
+ if( bitset->haveAll )
+ {
+ tr_bencInitStr( benc, "all", 3 );
+ }
+ else if( bitset->haveNone )
+ {
+ tr_bencInitStr( benc, "none", 4 );
+ }
+ else
+ {
+ const tr_bitfield * bf = &bitset->bitfield;
+ const size_t n = tr_bitfieldCountTrueBits( bf );
+
+ if( n == bf->bitCount )
+ {
+ tr_bencInitStr( benc, "all", 3 );
+ }
+ else if( n == 0 )
+ {
+ tr_bencInitStr( benc, "none", 4 );
+ }
+ else
+ {
+ tr_bencInitRaw( benc, bf->bits, bf->byteCount );
+ }
}
- return ret;
}
}
tr_bitset;
-void tr_bitsetReserve( tr_bitset * b, size_t size );
-void tr_bitsetConstructor( tr_bitset * b, size_t size );
-void tr_bitsetDestructor( tr_bitset * b );
+extern const tr_bitset TR_BITSET_INIT;
+
+void tr_bitsetConstruct( tr_bitset * b, size_t bitCount );
+void tr_bitsetDestruct( tr_bitset * b );
void tr_bitsetSetHaveAll( tr_bitset * b );
void tr_bitsetSetHaveNone( tr_bitset * b );
-int tr_bitsetAdd( tr_bitset * b, size_t i );
+void tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield );
+
+void tr_bitsetAdd( tr_bitset * b, size_t i );
+void tr_bitsetRem( tr_bitset * b, size_t i );
+void tr_bitsetRemRange ( tr_bitset * b, size_t begin, size_t end );
+
+struct tr_benc;
+tr_bool tr_bitsetFromBenc( tr_bitset * bitset, struct tr_benc * benc );
+void tr_bitsetToBenc( const tr_bitset * bitset, struct tr_benc * benc );
/***
****
double tr_bitsetPercent( const tr_bitset * b );
tr_bool tr_bitsetHas( const tr_bitset * b, const size_t nth );
+size_t tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end );
void tr_bitsetOr( tr_bitfield * a, const tr_bitset * b );
***/
static int
-findPiece( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece )
+findBlockPos( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t block )
{
struct cache_block key;
key.tor = torrent;
- key.block = tr_torPieceFirstBlock( torrent, piece );
+ key.block = block;
return tr_ptrArrayLowerBound( &cache->blocks, &key, cache_block_compare, NULL );
}
int
tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
{
+ int pos;
int err = 0;
- const tr_file * file = &torrent->info.files[i];
- const tr_block_index_t begin = tr_torPieceFirstBlock( torrent, file->firstPiece );
- const tr_block_index_t end = tr_torPieceFirstBlock( torrent, file->lastPiece ) + tr_torPieceCountBlocks( torrent, file->lastPiece );
- const int pos = findPiece( cache, torrent, file->firstPiece );
- dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu)", (int)i, (size_t)begin, (size_t)end );
+ tr_block_index_t first;
+ tr_block_index_t last;
+ tr_torGetFileBlockRange( torrent, i, &first, &last );
+ pos = findBlockPos( cache, torrent, first );
+ dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu]", (int)i, (size_t)first, (size_t)last );
/* flush out all the blocks in that file */
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
{
const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
if( b->tor != torrent ) break;
- if( ( b->block < begin ) || ( b->block >= end ) ) break;
+ if( ( b->block < first ) || ( b->block > last ) ) break;
err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
}
tr_cacheFlushTorrent( tr_cache * cache, tr_torrent * torrent )
{
int err = 0;
- const int pos = findPiece( cache, torrent, 0 );
+ const int pos = findBlockPos( cache, torrent, 0 );
/* flush out all the blocks in that torrent */
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
* $Id$
*/
-#include <assert.h>
-#include <string.h>
-
#include "transmission.h"
#include "completion.h"
#include "torrent.h"
-#include "torrent-magnet.h"
#include "utils.h"
+/***
+****
+***/
+
static void
tr_cpReset( tr_completion * cp )
{
- tr_bitfieldClear( &cp->pieceBitfield );
- tr_bitfieldClear( &cp->blockBitfield );
- memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
+ tr_bitsetSetHaveNone( &cp->blockBitset );
+ tr_free( cp->completeBlocks );
+ cp->completeBlocks = NULL;
cp->sizeNow = 0;
- cp->sizeWhenDoneIsDirty = 1;
- cp->blocksWantedIsDirty = 1;
- cp->haveValidIsDirty = 1;
+ cp->sizeWhenDoneIsDirty = TRUE;
+ cp->blocksWantedIsDirty = TRUE;
+ cp->haveValidIsDirty = TRUE;
}
tr_completion *
tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
{
cp->tor = tor;
- cp->completeBlocks = tr_new( uint16_t, tor->info.pieceCount );
- tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
- tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
+ cp->completeBlocks = NULL;
+ tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
tr_cpReset( cp );
return cp;
}
tr_cpDestruct( tr_completion * cp )
{
tr_free( cp->completeBlocks );
- tr_bitfieldDestruct( &cp->pieceBitfield );
- tr_bitfieldDestruct( &cp->blockBitfield );
+ tr_bitsetDestruct( &cp->blockBitset );
return cp;
}
+/***
+****
+***/
+
+static inline tr_bool
+isSeed( const tr_completion * cp )
+{
+ return cp->blockBitset.haveAll;
+}
+
+tr_completeness
+tr_cpGetStatus( const tr_completion * cp )
+{
+ if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
+ if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
+ if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
+ return TR_LEECH;
+}
+
+/* how many blocks are in this piece? */
+static inline uint16_t
+countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
+{
+ return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
+ : tor->blockCountInPiece;
+}
+
+static uint16_t *
+getCompleteBlocks( const tr_completion * ccp )
+{
+ if( ccp->completeBlocks == NULL )
+ {
+ tr_completion * cp = (tr_completion*) ccp;
+ cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
+ }
+
+ return ccp->completeBlocks;
+}
+
void
tr_cpInvalidateDND( tr_completion * cp )
{
- cp->sizeWhenDoneIsDirty = 1;
- cp->blocksWantedIsDirty = 1;
+ cp->sizeWhenDoneIsDirty = TRUE;
+ cp->blocksWantedIsDirty = TRUE;
}
tr_block_index_t
tr_cpBlocksMissing( const tr_completion * ccp )
{
+ if( isSeed( ccp ) )
+ return 0;
+
if( ccp->blocksWantedIsDirty )
{
- tr_completion * cp = (tr_completion *) ccp; /* mutable */
- const tr_torrent * tor = cp->tor;
- const tr_info * info = &tor->info;
tr_piece_index_t i;
tr_block_index_t wanted = 0;
tr_block_index_t complete = 0;
+ tr_completion * cp = (tr_completion *) ccp; /* mutable */
+ const uint16_t * complete_blocks = getCompleteBlocks( cp );
+ const tr_torrent * tor = ccp->tor;
+ const tr_info * info = &tor->info;
for( i = 0; i < info->pieceCount; ++i )
{
- if( info->pieces[i].dnd )
- continue;
-
- wanted += tr_torPieceCountBlocks( tor, i );
- complete += cp->completeBlocks[i];
+ if( !info->pieces[i].dnd )
+ {
+ wanted += countBlocksInPiece( tor, i );
+ complete += complete_blocks[i];
+ }
}
cp->blocksWantedLazy = wanted;
return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
}
-uint64_t
-tr_cpSizeWhenDone( const tr_completion * ccp )
+void
+tr_cpPieceRem( tr_completion * cp, tr_piece_index_t piece )
{
- if( ccp->sizeWhenDoneIsDirty )
- {
- tr_completion * cp = (tr_completion *) ccp; /* mutable */
- const tr_torrent * tor = cp->tor;
- const tr_info * info = &tor->info;
- tr_piece_index_t i;
- uint64_t size = 0;
+ tr_block_index_t i;
+ tr_block_index_t first;
+ tr_block_index_t last;
+ const tr_torrent * tor = cp->tor;
+ uint16_t * complete_blocks = getCompleteBlocks( cp );
- for( i = 0; i < info->pieceCount; ++i )
- {
- if( !info->pieces[i].dnd )
- {
- /* we want the piece... */
- size += tr_torPieceCountBytes( tor, i );
- }
- else if( tr_cpPieceIsComplete( cp, i ) )
- {
- /* we have the piece... */
- size += tr_torPieceCountBytes( tor, i );
- }
- else if( cp->completeBlocks[i] )
- {
- /* we have part of the piece... */
- const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
- const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
- tr_block_index_t j;
- for( j = b; j < e; ++j )
- if( tr_cpBlockIsCompleteFast( cp, j ) )
- size += tr_torBlockCountBytes( tor, j );
- }
- }
+ tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
+ for( i=first; i<=last; ++i )
+ if( tr_cpBlockIsComplete( cp, i ) )
+ cp->sizeNow -= tr_torBlockCountBytes( tor, i );
- cp->sizeWhenDoneLazy = size;
- cp->sizeWhenDoneIsDirty = 0;
- }
+ if( !tor->info.pieces[piece].dnd )
+ cp->blocksWantedCompleteLazy -= complete_blocks[piece];
- assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
- assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
- return ccp->sizeWhenDoneLazy;
+ cp->sizeWhenDoneIsDirty = TRUE;
+ cp->haveValidIsDirty = TRUE;
+ complete_blocks[piece] = 0;
+ tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
}
void
-tr_cpPieceAdd( tr_completion * cp,
- tr_piece_index_t piece )
+tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
{
- const tr_torrent * tor = cp->tor;
- const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
- const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
- tr_block_index_t i;
+ tr_block_index_t i;
+ tr_block_index_t first;
+ tr_block_index_t last;
+ tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
- for( i = start; i < end; ++i )
+ for( i=first; i<=last; ++i )
tr_cpBlockAdd( cp, i );
}
-void
-tr_cpPieceRem( tr_completion * cp,
- tr_piece_index_t piece )
-{
- const tr_torrent * tor = cp->tor;
- const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
- const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
- tr_block_index_t block;
-
- assert( cp );
- assert( piece < tor->info.pieceCount );
- assert( start < tor->blockCount );
- assert( start <= end );
- assert( end <= tor->blockCount );
-
- for( block = start; block < end; ++block )
- if( tr_cpBlockIsCompleteFast( cp, block ) )
- cp->sizeNow -= tr_torBlockCountBytes( tor, block );
-
- if( !tor->info.pieces[piece].dnd )
- cp->blocksWantedCompleteLazy -= cp->completeBlocks[piece];
-
- cp->sizeWhenDoneIsDirty = 1;
- cp->haveValidIsDirty = 1;
- cp->completeBlocks[piece] = 0;
- tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
- tr_bitfieldRem( &cp->pieceBitfield, piece );
-}
-
void
tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
{
if( !tr_cpBlockIsComplete( cp, block ) )
{
const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
- const int blockSize = tr_torBlockCountBytes( tor,
- block );
-
- ++cp->completeBlocks[piece];
+ const int blockSize = tr_torBlockCountBytes( tor, block );
- if( tr_cpPieceIsComplete( cp, piece ) )
- tr_bitfieldAdd( &cp->pieceBitfield, piece );
+ getCompleteBlocks(cp)[piece]++;
- tr_bitfieldAdd( &cp->blockBitfield, block );
+ tr_bitsetAdd( &cp->blockBitset, block );
cp->sizeNow += blockSize;
if( !tor->info.pieces[piece].dnd )
cp->blocksWantedCompleteLazy++;
- cp->haveValidIsDirty = 1;
- cp->sizeWhenDoneIsDirty = 1;
+ cp->sizeWhenDoneIsDirty = TRUE;
+ cp->haveValidIsDirty = TRUE;
}
}
-void
-tr_cpSetHaveAll( tr_completion * cp )
-{
- tr_piece_index_t i;
- tr_torrent * tor = cp->tor;
-
- tr_cpReset( cp );
-
- cp->sizeNow = tor->info.totalSize;
- tr_bitfieldAddRange( &cp->blockBitfield, 0, tor->blockCount );
- tr_bitfieldAddRange( &cp->pieceBitfield, 0, tor->info.pieceCount );
- for( i=0; i<tor->info.pieceCount; ++i )
- cp->completeBlocks[i] = tr_torPieceCountBlocks( tor, i );
- cp->sizeWhenDoneIsDirty = 1;
- cp->blocksWantedIsDirty = 1;
- cp->haveValidIsDirty = 1;
-}
-
-/* Initialize a completion object from a bitfield indicating which blocks we have */
tr_bool
-tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
+tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
{
tr_bool success = FALSE;
+ tr_torrent * tor = cp->tor;
- assert( cp );
- assert( blockBitfield );
+ /* start cp with a state where it thinks we have nothing */
+ tr_cpReset( cp );
- /* The bitfield of block flags is typically loaded from a resume file.
- Test the bitfield's length in case the resume file somehow got corrupted */
- if(( success = blockBitfield->byteCount == cp->blockBitfield.byteCount ))
+ if( blocks->haveAll )
{
- tr_block_index_t b = 0;
- tr_piece_index_t p = 0;
- uint32_t pieceBlock = 0;
- uint16_t completeBlocksInPiece = 0;
- tr_block_index_t completeBlocksInTorrent = 0;
- uint32_t blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
-
- /* start cp with a state where it thinks we have nothing */
- tr_cpReset( cp );
+ tr_bitsetSetHaveAll( &cp->blockBitset );
+ cp->sizeNow = tor->info.totalSize;
- /* init our block bitfield from the one passed in */
- memcpy( cp->blockBitfield.bits, blockBitfield->bits, blockBitfield->byteCount );
+ success = TRUE;
+ }
+ else if( blocks->haveNone )
+ {
+ /* already reset... */
+ success = TRUE;
+ }
+ else
+ {
+ const tr_bitfield * src = &blocks->bitfield;
+ tr_bitfield * tgt = &cp->blockBitset.bitfield;
- /* invalidate the fields that are lazy-evaluated */
- cp->sizeWhenDoneIsDirty = TRUE;
- cp->blocksWantedIsDirty = TRUE;
- cp->haveValidIsDirty = TRUE;
+ tr_bitfieldConstruct( tgt, tor->blockCount );
- /* to set the remaining fields, we walk through every block... */
- while( b < cp->tor->blockCount )
+ /* The bitfield of block flags is typically loaded from a resume file.
+ Test the bitfield's length in case the resume file is corrupt */
+ if(( success = src->byteCount == tgt->byteCount ))
{
- if( tr_bitfieldHasFast( blockBitfield, b ) )
- ++completeBlocksInPiece;
-
- ++b;
- ++pieceBlock;
-
- /* by the time we reach the end of a piece, we have enough info
- to update that piece's slot in cp.completeBlocks and cp.pieceBitfield */
- if( pieceBlock == blocksInCurrentPiece )
- {
- cp->completeBlocks[p] = completeBlocksInPiece;
- completeBlocksInTorrent += completeBlocksInPiece;
- if( completeBlocksInPiece == blocksInCurrentPiece )
- tr_bitfieldAdd( &cp->pieceBitfield, p );
-
- /* reset the per-piece counters because we're starting on a new piece now */
- ++p;
- completeBlocksInPiece = 0;
- pieceBlock = 0;
- blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
+ size_t i = 0;
+ uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
+
+ /* init our block bitfield from the one passed in */
+ memcpy( tgt->bits, src->bits, src->byteCount );
+
+ /* update cp.sizeNow and the cp.blockBitset flags */
+ i = tr_bitfieldCountTrueBits( tgt );
+ if( i == tor->blockCount ) {
+ tr_bitsetSetHaveAll( &cp->blockBitset );
+ cp->sizeNow = cp->tor->info.totalSize;
+ } else if( !i ) {
+ tr_bitsetSetHaveNone( &cp->blockBitset );
+ cp->sizeNow = 0;
+ } else {
+ cp->blockBitset.haveAll = cp->blockBitset.haveNone = FALSE;
+ cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
+ cp->sizeNow *= tor->blockSize;
+ if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
+ cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
}
- }
- /* update sizeNow */
- cp->sizeNow = completeBlocksInTorrent;
- cp->sizeNow *= tr_torBlockCountBytes( cp->tor, 0 );
- if( tr_bitfieldHasFast( &cp->blockBitfield, cp->tor->blockCount-1 ) ) {
- /* the last block is usually smaller than the other blocks,
- so handle that special case or cp->sizeNow might be too large */
- cp->sizeNow -= tr_torBlockCountBytes( cp->tor, 0 );
- cp->sizeNow += tr_torBlockCountBytes( cp->tor, cp->tor->blockCount-1 );
+ /* update complete_blocks_in_piece */
+ for( i=0; i<tor->info.pieceCount; ++i ) {
+ tr_block_index_t first, last;
+ tr_torGetPieceBlockRange( tor, i, &first, &last );
+ complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
+ }
}
}
****
***/
-tr_completeness
-tr_cpGetStatus( const tr_completion * cp )
-{
- if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
- if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
- if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
- return TR_LEECH;
-}
-
-static uint64_t
-calculateHaveValid( const tr_completion * ccp )
+uint64_t
+tr_cpHaveValid( const tr_completion * ccp )
{
- uint64_t b = 0;
- tr_piece_index_t i;
- const tr_torrent * tor = ccp->tor;
- const uint64_t pieceSize = tor->info.pieceSize;
- const uint64_t lastPieceSize = tor->lastPieceSize;
- const tr_piece_index_t lastPiece = tor->info.pieceCount - 1;
-
- if( !tr_torrentHasMetadata( tor ) )
- return 0;
+ if( ccp->haveValidIsDirty )
+ {
+ tr_piece_index_t i;
+ uint64_t size = 0;
+ tr_completion * cp = (tr_completion *) ccp; /* mutable */
+ const tr_torrent * tor = ccp->tor;
+ const tr_info * info = &tor->info;
- for( i=0; i!=lastPiece; ++i )
- if( tr_cpPieceIsComplete( ccp, i ) )
- b += pieceSize;
+ for( i=0; i<info->pieceCount; ++i )
+ if( tr_cpPieceIsComplete( ccp, i ) )
+ size += tr_torPieceCountBytes( tor, i );
- if( tr_cpPieceIsComplete( ccp, lastPiece ) )
- b += lastPieceSize;
+ cp->haveValidIsDirty = FALSE;
+ cp->haveValidLazy = size;
+ }
- return b;
+ return ccp->haveValidLazy;
}
uint64_t
-tr_cpHaveValid( const tr_completion * ccp )
+tr_cpSizeWhenDone( const tr_completion * ccp )
{
- if( ccp->haveValidIsDirty )
+ if( ccp->sizeWhenDoneIsDirty )
{
- tr_completion * cp = (tr_completion *) ccp; /* mutable */
- cp->haveValidLazy = calculateHaveValid( ccp );
- cp->haveValidIsDirty = 0;
+ tr_piece_index_t i;
+ uint64_t size = 0;
+ tr_completion * cp = (tr_completion *) ccp; /* mutable */
+ const tr_torrent * tor = ccp->tor;
+ const tr_info * info = &tor->info;
+
+ for( i=0; i<info->pieceCount; ++i )
+ if( !info->pieces[i].dnd || tr_cpPieceIsComplete( cp, i ) )
+ size += tr_torPieceCountBytes( tor, i );
+
+ cp->sizeWhenDoneIsDirty = FALSE;
+ cp->sizeWhenDoneLazy = size;
}
- return ccp->haveValidLazy;
+ return ccp->sizeWhenDoneLazy;
}
void
-tr_cpGetAmountDone( const tr_completion * cp,
- float * tab,
- int tabCount )
+tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
{
- int i;
- const tr_torrent * tor = cp->tor;
- const float interval = tor->info.pieceCount / (float)tabCount;
- const int isSeed = tr_cpGetStatus( cp ) == TR_SEED;
+ int i, b;
+ const int span = cp->tor->blockCount / tabCount;
- for( i = 0; i < tabCount; ++i )
- {
- const tr_piece_index_t piece = i * interval;
-
- if( tor == NULL )
- tab[i] = 0.0f;
- else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
- tab[i] = 1.0f;
- else
- tab[i] = (float)cp->completeBlocks[piece] /
- tr_torPieceCountBlocks( tor, piece );
- }
+ for( i=b=0; i<tabCount; ++i, b+=span )
+ tab[i] = tr_bitsetCountRange(&cp->blockBitset,b,b+span) / (float)span;
}
int
-tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
+tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
{
- return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
-}
-
+ if( isSeed( cp ) )
+ return 0;
-tr_bool
-tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
-{
- return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
+ return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
}
tr_bool
-tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t fileIndex )
+tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
{
- tr_block_index_t block;
+ tr_block_index_t f, l;
- const tr_torrent * tor = cp->tor;
- const tr_file * file = &tor->info.files[fileIndex];
+ if( cp->tor->info.files[i].length == 0 )
+ return TRUE;
- if( file->firstPiece == file->lastPiece )
- {
- const tr_block_index_t firstBlock = file->offset / tor->blockSize;
- const tr_block_index_t lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
- for( block=firstBlock; block<=lastBlock; ++block )
- if( !tr_cpBlockIsCompleteFast( cp, block ) )
- return FALSE;
- }
- else
- {
- tr_piece_index_t piece;
- tr_block_index_t firstBlock;
- tr_block_index_t firstBlockInLastPiece;
- tr_block_index_t lastBlock;
- tr_block_index_t lastBlockInFirstPiece;
- uint64_t lastByteInFirstPiece;
- uint64_t firstByteInLastPiece;
-
- /* go piece-by-piece in the middle pieces... it's faster than block-by-block */
- for( piece=file->firstPiece+1; piece<file->lastPiece; ++piece )
- if( !tr_cpPieceIsComplete( cp, piece ) )
- return FALSE;
-
- /* go block-by-block in the first piece */
- firstBlock = file->offset / tor->blockSize;
- lastByteInFirstPiece = ( (uint64_t)(file->firstPiece+1) * tor->info.pieceSize ) - 1;
- lastBlockInFirstPiece = lastByteInFirstPiece / tor->blockSize;
- assert( lastBlockInFirstPiece >= firstBlock );
- assert( lastBlockInFirstPiece - firstBlock <= tr_torPieceCountBlocks( tor, file->firstPiece ) );
- for( block=firstBlock; block<=lastBlockInFirstPiece; ++block )
- if( !tr_cpBlockIsCompleteFast( cp, block ) )
- return FALSE;
-
- /* go block-by-block in the last piece */
- lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
- firstByteInLastPiece = (uint64_t)file->lastPiece * tor->info.pieceSize;
- firstBlockInLastPiece = firstByteInLastPiece / tor->blockSize;
- assert( firstBlockInLastPiece <= lastBlock );
- assert( firstBlockInLastPiece >= firstBlock );
- assert( firstBlockInLastPiece >= lastBlockInFirstPiece );
- assert( lastBlock - firstBlockInLastPiece <= tr_torPieceCountBlocks( tor, file->lastPiece ) );
- for( block=firstBlockInLastPiece; block<=lastBlock; ++block )
- if( !tr_cpBlockIsCompleteFast( cp, block ) )
- return FALSE;
- }
+ tr_torGetFileBlockRange( cp->tor, i, &f, &l );
+ return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
+}
+
+tr_bitfield *
+tr_cpCreatePieceBitfield( const tr_completion * cp )
+{
+ tr_piece_index_t i;
+ const tr_piece_index_t n = cp->tor->info.pieceCount;
+ tr_bitfield * bf = tr_bitfieldNew( n );
- return TRUE;
+ for( i=0; i<n; ++i )
+ if( tr_cpPieceIsComplete( cp, i ) )
+ tr_bitfieldAdd( bf, i );
+ return bf;
}
#include <assert.h>
#include "transmission.h"
-#include "bitfield.h"
+#include "bitset.h"
+#include "utils.h" /* tr_getRatio() */
typedef struct tr_completion
{
tr_torrent * tor;
/* do we have this block? */
- tr_bitfield blockBitfield;
-
- /* do we have this piece? */
- tr_bitfield pieceBitfield;
+ tr_bitset blockBitset;
/* a block is complete if and only if we have it */
uint16_t * completeBlocks;
*** General
**/
-tr_completeness tr_cpGetStatus( const tr_completion * );
+tr_completeness tr_cpGetStatus( const tr_completion * );
-uint64_t tr_cpHaveValid( const tr_completion * );
+uint64_t tr_cpHaveValid( const tr_completion * );
-tr_block_index_t tr_cpBlocksMissing( const tr_completion * );
+tr_block_index_t tr_cpBlocksMissing( const tr_completion * );
-uint64_t tr_cpSizeWhenDone( const tr_completion * );
+uint64_t tr_cpSizeWhenDone( const tr_completion * );
-void tr_cpInvalidateDND( tr_completion * );
+void tr_cpInvalidateDND( tr_completion * );
-void tr_cpGetAmountDone( const tr_completion * completion,
- float * tab,
- int tabCount );
+void tr_cpGetAmountDone( const tr_completion * completion,
+ float * tab,
+ int tabCount );
static inline uint64_t tr_cpHaveTotal( const tr_completion * cp )
{
*** Pieces
**/
-int tr_cpMissingBlocksInPiece( const tr_completion * cp,
- tr_piece_index_t piece );
+int tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i );
-tr_bool tr_cpPieceIsComplete( const tr_completion * cp,
- tr_piece_index_t piece );
+static inline tr_bool
+tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t i )
+{
+ return tr_cpMissingBlocksInPiece( cp, i ) == 0;
+}
-void tr_cpPieceAdd( tr_completion * completion,
- tr_piece_index_t piece );
+void tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t i );
-void tr_cpPieceRem( tr_completion * completion,
- tr_piece_index_t piece );
+void tr_cpPieceRem( tr_completion * cp, tr_piece_index_t i );
tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
*** Blocks
**/
-static inline tr_bool tr_cpBlockIsCompleteFast( const tr_completion * cp, tr_block_index_t block )
+static inline tr_bool
+tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t i )
{
- return tr_bitfieldHasFast( &cp->blockBitfield, block );
+ return tr_bitsetHas( &cp->blockBitset, i );
}
-static inline tr_bool tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
-{
- return tr_bitfieldHas( &cp->blockBitfield, block );
-}
+void tr_cpBlockAdd( tr_completion * cp, tr_block_index_t i );
-void tr_cpBlockAdd( tr_completion * completion,
- tr_block_index_t block );
-
-tr_bool tr_cpBlockBitfieldSet( tr_completion * completion,
- struct tr_bitfield * blocks );
-
-void tr_cpSetHaveAll( tr_completion * completion );
+tr_bool tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks );
/***
****
***/
-static inline const struct tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp ) {
- return &cp->pieceBitfield;
+static inline const tr_bitset *
+tr_cpBlockBitset( const tr_completion * cp )
+{
+ return &cp->blockBitset;
}
-static inline const struct tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp ) {
- assert( cp );
- assert( cp->blockBitfield.bits );
- assert( cp->blockBitfield.bitCount );
- return &cp->blockBitfield;
-}
+tr_bitfield * tr_cpCreatePieceBitfield( const tr_completion * cp );
#endif
{
tr_peer * peer = tr_new0( tr_peer, 1 );
- tr_bitsetConstructor( &peer->have, 0 );
+ peer->have = TR_BITSET_INIT;
peer->atom = atom;
atom->peer = peer;
tr_historyFree( peer->cancelsSentToClient );
tr_historyFree( peer->cancelsSentToPeer );
- tr_bitsetDestructor( &peer->have );
+ tr_bitsetDestruct( &peer->have );
tr_bitfieldFree( peer->blame );
tr_free( peer->client );
peer->atom->peer = NULL;
/* if the peer has this piece that we want... */
if( tr_bitsetHas( have, p->index ) )
{
- tr_block_index_t b = tr_torPieceFirstBlock( tor, p->index );
- const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, p->index );
+ tr_block_index_t b;
+ tr_block_index_t first;
+ tr_block_index_t last;
tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
- for( ; b!=e && got<numwant; ++b )
+ tr_torGetPieceBlockRange( tor, p->index, &first, &last );
+
+ for( b=first; b<=last && got<numwant; ++b )
{
int peerCount;
tr_peer ** peers;
/* don't request blocks we've already got */
- if( tr_cpBlockIsCompleteFast( &tor->completion, b ) )
+ if( tr_cpBlockIsComplete( &tor->completion, b ) )
continue;
/* always add peer if this block has no peers yet */
/* request the blocks that we don't have in this piece */
{
- tr_block_index_t block;
+ tr_block_index_t b;
+ tr_block_index_t first;
+ tr_block_index_t last;
const tr_torrent * tor = t->tor;
- const tr_block_index_t start = tr_torPieceFirstBlock( tor, pieceIndex );
- const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, pieceIndex );
- for( block=start; block<end; ++block )
+ tr_torGetPieceBlockRange( t->tor, pieceIndex, &first, &last );
+
+ for( b=first; b<=last; ++b )
{
- if( !tr_cpBlockIsComplete( tor->completion, block ) )
+ if( !tr_cpBlockIsComplete( tor->completion, b ) )
{
- const uint32_t offset = getBlockOffsetInPiece( tor, block );
- const uint32_t length = tr_torBlockCountBytes( tor, block );
+ const uint32_t offset = getBlockOffsetInPiece( tor, b );
+ const uint32_t length = tr_torBlockCountBytes( tor, b );
tr_peerMsgsAddRequest( peer->msgs, pieceIndex, offset, length );
incrementPieceRequests( t, pieceIndex );
}
HIGH_PRIORITY_INTERVAL_SECS = 2,
LOW_PRIORITY_INTERVAL_SECS = 10,
- /* number of pieces to remove from the bitfield when
- * lazy bitfields are turned on */
- LAZY_PIECE_COUNT = 26,
-
/* number of pieces we'll allow in our fast set */
MAX_FAST_SET_SIZE = 3,
uint32_t length;
};
-static uint32_t
-getBlockOffsetInPiece( const tr_torrent * tor, uint64_t b )
-{
- const uint64_t piecePos = tor->info.pieceSize * tr_torBlockPiece( tor, b );
- const uint64_t blockPos = tor->blockSize * b;
- assert( blockPos >= piecePos );
- return (uint32_t)( blockPos - piecePos );
-}
-
static void
blockToReq( const tr_torrent * tor,
tr_block_index_t block,
struct peer_request * setme )
{
- assert( setme != NULL );
-
- setme->index = tr_torBlockPiece( tor, block );
- setme->offset = getBlockOffsetInPiece( tor, block );
- setme->length = tr_torBlockCountBytes( tor, block );
+ tr_torrentGetBlockLocation( tor, block, &setme->index,
+ &setme->offset,
+ &setme->length );
}
/**
}
/* a peer can send the same HAVE message twice... */
- if( !tr_bitsetHas( &msgs->peer->have, ui32 ) )
- if( !tr_bitsetAdd( &msgs->peer->have, ui32 ) )
- fireClientGotHave( msgs, ui32 );
+ if( !tr_bitsetHas( &msgs->peer->have, ui32 ) ) {
+ tr_bitsetAdd( &msgs->peer->have, ui32 );
+ fireClientGotHave( msgs, ui32 );
+ }
updatePeerProgress( msgs );
break;
case BT_BITFIELD: {
+ tr_bitfield tmp = TR_BITFIELD_INIT;
const size_t bitCount = tr_torrentHasMetadata( msgs->torrent )
? msgs->torrent->info.pieceCount
: msglen * 8;
+ tr_bitfieldConstruct( &tmp, bitCount );
dbgmsg( msgs, "got a bitfield" );
- tr_bitsetReserve( &msgs->peer->have, bitCount );
- tr_peerIoReadBytes( msgs->peer->io, inbuf,
- msgs->peer->have.bitfield.bits, msglen );
- fireClientGotBitfield( msgs, &msgs->peer->have.bitfield );
+ tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp.bits, msglen );
+ tr_bitsetSetBitfield( &msgs->peer->have, &tmp );
+ fireClientGotBitfield( msgs, &tmp );
+ tr_bitfieldDestruct( &tmp );
updatePeerProgress( msgs );
break;
}
sendBitfield( tr_peermsgs * msgs )
{
struct evbuffer * out = msgs->outMessages;
- tr_bitfield * field;
- tr_piece_index_t lazyPieces[LAZY_PIECE_COUNT];
- size_t i;
- size_t lazyCount = 0;
+ tr_bitfield * bf = tr_cpCreatePieceBitfield( &msgs->torrent->completion );
- field = tr_bitfieldDup( tr_cpPieceBitfield( &msgs->torrent->completion ) );
-
- if( tr_sessionIsLazyBitfieldEnabled( getSession( msgs ) ) )
- {
- /** Lazy bitfields aren't a high priority or secure, so I'm opting for
- speed over a truly random sample -- let's limit the pool size to
- the first 1000 pieces so large torrents don't bog things down */
- size_t poolSize;
- const size_t maxPoolSize = MIN( msgs->torrent->info.pieceCount, 1000 );
- tr_piece_index_t * pool = tr_new( tr_piece_index_t, maxPoolSize );
-
- /* build the pool */
- for( i=poolSize=0; i<maxPoolSize; ++i )
- if( tr_bitfieldHas( field, i ) )
- pool[poolSize++] = i;
-
- /* pull random piece indices from the pool */
- while( ( poolSize > 0 ) && ( lazyCount < LAZY_PIECE_COUNT ) )
- {
- const int pos = tr_cryptoWeakRandInt( poolSize );
- const tr_piece_index_t piece = pool[pos];
- tr_bitfieldRem( field, piece );
- lazyPieces[lazyCount++] = piece;
- pool[pos] = pool[--poolSize];
- }
-
- /* cleanup */
- tr_free( pool );
- }
-
- evbuffer_add_uint32( out, sizeof( uint8_t ) + field->byteCount );
+ evbuffer_add_uint32( out, sizeof( uint8_t ) + bf->byteCount );
evbuffer_add_uint8 ( out, BT_BITFIELD );
- evbuffer_add ( out, field->bits, field->byteCount );
- dbgmsg( msgs, "sending bitfield... outMessage size is now %zu",
- evbuffer_get_length( out ) );
+ evbuffer_add ( out, bf->bits, bf->byteCount );
+ dbgmsg( msgs, "sending bitfield... outMessage size is now %zu", evbuffer_get_length( out ) );
pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
- for( i = 0; i < lazyCount; ++i )
- protocolSendHave( msgs, lazyPieces[i] );
-
- tr_bitfieldFree( field );
+ tr_bitfieldFree( bf );
}
static void
{
const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
- if( fext && ( tr_cpGetStatus( &msgs->torrent->completion ) == TR_SEED ) )
+ if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveAll ) )
{
protocolSendHaveAll( msgs );
}
- else if( fext && ( tr_cpHaveValid( &msgs->torrent->completion ) == 0 ) )
+ else if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveNone ) )
{
protocolSendHaveNone( msgs );
}
#include "transmission.h"
#include "bencode.h"
+#include "bitset.h"
#include "completion.h"
#include "metainfo.h" /* tr_metainfoGetBasename() */
#include "peer-mgr.h" /* pex */
#define KEY_PROGRESS_CHECKTIME "time-checked"
#define KEY_PROGRESS_MTIMES "mtimes"
#define KEY_PROGRESS_BITFIELD "bitfield"
+#define KEY_PROGRESS_BLOCKS "blocks"
#define KEY_PROGRESS_HAVE "have"
enum
***/
static void
-saveProgress( tr_benc * dict, const tr_torrent * tor )
+saveProgress( tr_benc * dict, tr_torrent * tor )
{
tr_benc * l;
tr_benc * prog;
tr_file_index_t fi;
- const struct tr_bitfield * bitfield;
const tr_info * inf = tr_torrentInfo( tor );
const time_t now = tr_time( );
if( tor->completeness == TR_SEED )
tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" );
- /* add the pieces bitfield */
- bitfield = tr_cpBlockBitfield( &tor->completion );
- tr_bencDictAddRaw( prog, KEY_PROGRESS_BITFIELD, bitfield->bits,
- bitfield->byteCount );
+ /* add the blocks bitfield */
+ tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ),
+ tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) );
}
static uint64_t
const uint8_t * raw;
size_t rawlen;
tr_benc * l;
+ tr_benc * b;
+ struct tr_bitset bitset = TR_BITSET_INIT;
if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
{
}
err = NULL;
- if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
+
+ if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
+ {
+ if( !tr_bitsetFromBenc( &bitset, b ) )
+ err = "Invalid value for PIECES";
+ }
+ else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
{
if( !strcmp( str, "all" ) )
- tr_cpSetHaveAll( &tor->completion );
+ tr_bitsetSetHaveAll( &bitset );
else
err = "Invalid value for HAVE";
}
else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
{
- tr_bitfield tmp;
- tmp.byteCount = rawlen;
- tmp.bitCount = tmp.byteCount * 8;
- tmp.bits = (uint8_t*) raw;
- if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
- err = "Error loading bitfield";
+ bitset.bitfield.bits = (void*) raw;
+ bitset.bitfield.byteCount = rawlen;
+ bitset.bitfield.bitCount = rawlen * 8;
}
- else err = "Couldn't find 'have' or 'bitfield'";
+ else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
+ if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) )
+ err = "Error loading bitfield";
if( err != NULL )
tr_tordbg( tor, "Torrent needs to be verified - %s", err );
else if( tr_streq( key, keylen, "peersSendingToUs" ) )
tr_bencDictAddInt( d, key, st->peersSendingToUs );
else if( tr_streq( key, keylen, "pieces" ) ) {
- const tr_bitfield * pieces = tr_cpPieceBitfield( &tor->completion );
- char * str = tr_base64_encode( pieces->bits, pieces->byteCount, NULL );
+ tr_bitfield * bf = tr_cpCreatePieceBitfield( &tor->completion );
+ char * str = tr_base64_encode( bf->bits, bf->byteCount, NULL );
tr_bencDictAddStr( d, key, str!=NULL ? str : "" );
tr_free( str );
+ tr_bitfieldFree( bf );
}
else if( tr_streq( key, keylen, "pieceCount" ) )
tr_bencDictAddInt( d, key, inf->pieceCount );
tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, FALSE );
tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_getDefaultDownloadDir( ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE );
- tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD, TRUE );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF );
tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT, atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, tr_sessionIsIdleLimited( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_sessionGetIncompleteDir( s ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, tr_sessionIsIncompleteDirEnabled( s ) );
- tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD, s->useLazyBitfield );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, tr_getMessageLevel( ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT, tr_fdGetFileLimit( s ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, tr_sessionGetPeerLimit( s ) );
/* misc features */
if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
tr_sessionSetCacheLimit_MB( session, i );
- if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal ) )
- tr_sessionSetLazyBitfieldEnabled( session, boolVal );
if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
tr_sessionSetPeerLimitPerTorrent( session, i );
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal ) )
if( f->length )
{
- const tr_block_index_t firstBlock = f->offset / tor->blockSize;
- const uint64_t lastByte = f->offset + f->length - 1;
- const tr_block_index_t lastBlock = lastByte / tor->blockSize;
+ tr_block_index_t first;
+ tr_block_index_t last;
+ tr_torGetFileBlockRange( tor, index, &first, &last );
- if( firstBlock == lastBlock )
+ if( first == last )
{
- if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
+ if( tr_cpBlockIsComplete( &tor->completion, first ) )
total = f->length;
}
else
{
- tr_block_index_t i;
-
/* the first block */
- if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
+ if( tr_cpBlockIsComplete( &tor->completion, first ) )
total += tor->blockSize - ( f->offset % tor->blockSize );
/* the middle blocks */
- if( f->firstPiece == f->lastPiece )
- {
- for( i=firstBlock+1; i<lastBlock; ++i )
- if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
- total += tor->blockSize;
- }
- else
- {
- uint64_t b = 0;
- const tr_block_index_t firstBlockOfLastPiece
- = tr_torPieceFirstBlock( tor, f->lastPiece );
- const tr_block_index_t lastBlockOfFirstPiece
- = tr_torPieceFirstBlock( tor, f->firstPiece )
- + tr_torPieceCountBlocks( tor, f->firstPiece ) - 1;
-
- /* the rest of the first piece */
- for( i=firstBlock+1; i<lastBlock && i<=lastBlockOfFirstPiece; ++i )
- if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
- ++b;
-
- /* the middle pieces */
- if( f->firstPiece + 1 < f->lastPiece )
- for( i=f->firstPiece+1; i<f->lastPiece; ++i )
- b += tor->blockCountInPiece - tr_cpMissingBlocksInPiece( &tor->completion, i );
-
- /* the rest of the last piece */
- for( i=firstBlockOfLastPiece; i<lastBlock; ++i )
- if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
- ++b;
-
- b *= tor->blockSize;
- total += b;
+ if( first + 1 < last ) {
+ uint64_t u = tr_bitsetCountRange( tr_cpBlockBitset( &tor->completion ), first+1, last );
+ u *= tor->blockSize;
+ total += u;
}
/* the last block */
- if( tr_cpBlockIsCompleteFast( &tor->completion, lastBlock ) )
- total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * lastBlock );
+ if( tr_cpBlockIsComplete( &tor->completion, last ) )
+ total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * last );
}
}
****
***/
+void
+tr_torrentGetBlockLocation( const tr_torrent * tor,
+ tr_block_index_t block,
+ tr_piece_index_t * piece,
+ uint32_t * offset,
+ uint32_t * length )
+{
+ uint64_t pos = block;
+ pos *= tor->blockSize;
+ *piece = pos / tor->info.pieceSize;
+ *offset = pos - ( *piece * tor->info.pieceSize );
+ *length = tr_torBlockCountBytes( tor, block );
+}
+
+
tr_block_index_t
_tr_block( const tr_torrent * tor,
tr_piece_index_t index,
return ret;
}
+void
+tr_torGetFileBlockRange( const tr_torrent * tor,
+ const tr_file_index_t file,
+ tr_block_index_t * first,
+ tr_block_index_t * last )
+{
+ const tr_file * f = &tor->info.files[file];
+ uint64_t offset = f->offset;
+ *first = offset / tor->blockSize;
+ if( !f->length )
+ *last = *first;
+ else {
+ offset += f->length - 1;
+ *last = offset / tor->blockSize;
+ }
+}
+
+void
+tr_torGetPieceBlockRange( const tr_torrent * tor,
+ const tr_piece_index_t piece,
+ tr_block_index_t * first,
+ tr_block_index_t * last )
+{
+ uint64_t offset = tor->info.pieceSize;
+ offset *= piece;
+ *first = offset / tor->blockSize;
+ offset += ( tr_torPieceCountBytes( tor, piece ) - 1 );
+ *last = offset / tor->blockSize;
+}
+
+
/***
****
***/
uint32_t offset,
uint32_t length );
+void tr_torrentGetBlockLocation( const tr_torrent * tor,
+ tr_block_index_t block,
+ tr_piece_index_t * piece,
+ uint32_t * offset,
+ uint32_t * length );
+
+void tr_torGetFileBlockRange( const tr_torrent * tor,
+ const tr_file_index_t file,
+ tr_block_index_t * first,
+ tr_block_index_t * last );
+
+void tr_torGetPieceBlockRange( const tr_torrent * tor,
+ const tr_piece_index_t piece,
+ tr_block_index_t * first,
+ tr_block_index_t * last );
+
void tr_torrentInitFilePriority( tr_torrent * tor,
tr_file_index_t fileIndex,
tr_priority_t priority );
return current ? current->next : session->torrentList;
}
-/* get the index of this piece's first block */
-static inline tr_block_index_t
-tr_torPieceFirstBlock( const tr_torrent * tor, const tr_piece_index_t piece )
-{
- return piece * tor->blockCountInPiece;
-}
-
/* what piece index is this block in? */
static inline tr_piece_index_t
tr_torBlockPiece( const tr_torrent * tor, const tr_block_index_t block )
return block / tor->blockCountInPiece;
}
-/* how many blocks are in this piece? */
-static inline uint16_t
-tr_torPieceCountBlocks( const tr_torrent * tor, const tr_piece_index_t piece )
-{
- return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
- : tor->blockCountInPiece;
-}
-
/* how many bytes are in this piece? */
static inline uint32_t
tr_torPieceCountBytes( const tr_torrent * tor, const tr_piece_index_t piece )
#define TR_PREFS_KEY_IDLE_LIMIT_ENABLED "idle-seeding-limit-enabled"
#define TR_PREFS_KEY_INCOMPLETE_DIR "incomplete-dir"
#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED "incomplete-dir-enabled"
-#define TR_PREFS_KEY_LAZY_BITFIELD "lazy-bitfield-enabled"
#define TR_PREFS_KEY_MSGLEVEL "message-level"
#define TR_PREFS_KEY_OPEN_FILE_LIMIT "open-file-limit"
#define TR_PREFS_KEY_PEER_LIMIT_GLOBAL "peer-limit-global"
}
#endif
+static int
+test_bitfield_count_range( void )
+{
+ int i;
+ int n;
+ int begin;
+ int end;
+ int count1;
+ int count2;
+ const int bitCount = 100 + tr_cryptoWeakRandInt( 1000 );
+ tr_bitfield * bf;
+
+ /* generate a random bitfield */
+ bf = tr_bitfieldNew( bitCount );
+ for( i=0, n=tr_cryptoWeakRandInt(bitCount); i<n; ++i )
+ tr_bitfieldAdd( bf, tr_cryptoWeakRandInt(bitCount) );
+
+ begin = tr_cryptoWeakRandInt( bitCount );
+ do {
+ end = tr_cryptoWeakRandInt( bitCount );
+ } while( end == begin );
+ if( end < begin ) {
+ const int tmp = begin;
+ begin = end;
+ end = tmp;
+ }
+
+ count1 = 0;
+ for( i=begin; i<end; ++i )
+ if( tr_bitfieldHas( bf, i ) )
+ ++count1;
+ count2 = tr_bitfieldCountRange( bf, begin, end );
+ check( count1 == count2 );
+
+ tr_bitfieldFree( bf );
+ return 0;
+}
+
static int
test_bitfields( void )
{
return 0;
}
+struct blah
+{
+ uint8_t hash[SHA_DIGEST_LENGTH]; /* pieces hash */
+ int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
+ int8_t dnd; /* "do not download" flag */
+ time_t timeChecked; /* the last time we tested this piece */
+};
+
+
int
main( void )
{
int i;
int l;
+fprintf( stderr, "sizeof time_t %zu\n", sizeof(time_t));
+fprintf( stderr, "sizeof char[20] %zu\n", (size_t)20);
+fprintf( stderr, "sizeof uint8_t %zu\n", sizeof(uint8_t));
+fprintf( stderr, "sizeof blah %zu\n", sizeof(struct blah));
+return 0;
+
/* base64 */
out = tr_base64_encode( "YOYO!", -1, &len );
check( out );
if( ( i = test_bitfields( ) ) )
return i;
+ /* bitfield count range */
+ for( l=0; l<1000000; ++l )
+ if(( i = test_bitfield_count_range( )))
+ return i;
+
return 0;
}
static void
webseed_free( struct tr_webseed * w )
{
- tr_bitsetDestructor( &w->parent.have );
+ tr_bitsetDestruct( &w->parent.have );
tr_free( w->parent.client );
event_free( w->timer );
{
tr_peer_event e = TR_PEER_EVENT_INIT;
e.eventType = TR_PEER_CLIENT_GOT_REJ;
- e.pieceIndex = tr_torBlockPiece( tor, block );
- e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
- e.length = tr_torBlockCountBytes( tor, block );
+ tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
publish( w, &e );
}
{
tr_peer_event e = TR_PEER_EVENT_INIT;
e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
- e.pieceIndex = tr_torBlockPiece( tor, block );
- e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
- e.length = tr_torBlockCountBytes( tor, block );
+ tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
publish( w, &e );
}
peer->peerIsChoked = TRUE;
peer->clientIsInterested = !tr_torrentIsSeed( tor );
- tr_bitsetConstructor( &peer->have, tor->info.pieceCount );
- tr_bitsetSetHaveAll( &peer->have );
peer->progress = 1.0;
peer->client = tr_strdup( "webseed" );
+ peer->have = TR_BITSET_INIT;
+ tr_bitsetSetHaveAll( &peer->have );
w->torrent_id = tr_torrentId( tor );
w->session = tor->session;