Esempio n. 1
0
tr_completion*
tr_cpDestruct( tr_completion * cp )
{
    tr_free( cp->completeBlocks );
    tr_bitfieldDestruct( &cp->pieceBitfield );
    tr_bitfieldDestruct( &cp->blockBitfield );
    return cp;
}
Esempio n. 2
0
static int
test_bitfields (void)
{
  unsigned int i;
  unsigned int bitcount = 500;
  tr_bitfield field;

  tr_bitfieldConstruct (&field, bitcount);

  /* test tr_bitfieldAdd */
  for (i=0; i<bitcount; i++)
    if (! (i % 7))
      tr_bitfieldAdd (&field, i);
  for (i=0; i<bitcount; i++)
    check (tr_bitfieldHas (&field, i) == (! (i % 7)));

  /* test tr_bitfieldAddRange */
  tr_bitfieldAddRange (&field, 0, bitcount);
  for (i=0; i<bitcount; i++)
    check (tr_bitfieldHas (&field, i));

  /* test tr_bitfieldRemRange in the middle of a boundary */
  tr_bitfieldRemRange (&field, 4, 21);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((i < 4) || (i >= 21)));

  /* test tr_bitfieldRemRange on the boundaries */
  tr_bitfieldAddRange (&field, 0, 64);
  tr_bitfieldRemRange (&field, 8, 24);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((i < 8) || (i >= 24)));

  /* test tr_bitfieldRemRange when begin & end is on the same word */
  tr_bitfieldAddRange (&field, 0, 64);
  tr_bitfieldRemRange (&field, 4, 5);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((i < 4) || (i >= 5)));

  /* test tr_bitfieldAddRange */
  tr_bitfieldRemRange (&field, 0, 64);
  tr_bitfieldAddRange (&field, 4, 21);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((4 <= i) && (i < 21)));

  /* test tr_bitfieldAddRange on the boundaries */
  tr_bitfieldRemRange (&field, 0, 64);
  tr_bitfieldAddRange (&field, 8, 24);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((8 <= i) && (i < 24)));

  /* test tr_bitfieldAddRange when begin & end is on the same word */
  tr_bitfieldRemRange (&field, 0, 64);
  tr_bitfieldAddRange (&field, 4, 5);
  for (i=0; i<64; i++)
    check (tr_bitfieldHas (&field, i) == ((4 <= i) && (i < 5)));

  tr_bitfieldDestruct (&field);
  return 0;
}
Esempio n. 3
0
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 */
  tr_bitfieldConstruct (&bf, 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);

  /* ensure end <= begin */
  if (end < begin)
    {
      const int tmp = begin;
      begin = end;
      end = tmp;
    }

  /* test the bitfield */
  count1 = 0;
  for (i=begin; i<end; ++i)
    if (tr_bitfieldHas (&bf, i))
      ++count1;
  count2 = tr_bitfieldCountRange (&bf, begin, end);
  check (count1 == count2);

  /* cleanup */
  tr_bitfieldDestruct (&bf);
  return 0;
}
Esempio n. 4
0
static uint64_t
loadProgress( tr_benc * dict, tr_torrent * tor )
{
    size_t i, n;
    uint64_t ret = 0;
    tr_benc * prog;
    const tr_info * inf = tr_torrentInfo( tor );

    for( i=0, n=inf->pieceCount; i<n; ++i )
        inf->pieces[i].timeChecked = 0;

    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &prog ) )
    {
        const char * err;
        const char * str;
        const uint8_t * raw;
        size_t rawlen;
        tr_benc * l;
        tr_benc * b;
        struct tr_bitfield blocks = TR_BITFIELD_INIT;

        if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
        {
            /* per-piece timestamps were added in 2.20.

               If some of a file's pieces have been checked more recently than
               the file's mtime, and some lest recently, then that file will
               have a list containing timestamps for each piece.

               However, the most common use case is that the file doesn't change
               after it's downloaded. To reduce overhead in the .resume file,
               only a single timestamp is saved for the file if *all* or *none*
               of the pieces were tested more recently than the file's mtime. */

            tr_file_index_t fi;

            for( fi=0; fi<inf->fileCount; ++fi )
            {
                tr_benc * b = tr_bencListChild( l, fi );
                const tr_file * f = &inf->files[fi];
                tr_piece * p = &inf->pieces[f->firstPiece];
                const tr_piece * pend = &inf->pieces[f->lastPiece]+1;

                if( tr_bencIsInt( b ) )
                {
                    int64_t t;
                    tr_bencGetInt( b, &t );
                    for( ; p!=pend; ++p )
                        p->timeChecked = (time_t)t;
                }
                else if( tr_bencIsList( b ) )
                {
                    int i = 0;
                    int64_t offset = 0;
                    const int pieces = f->lastPiece + 1 - f->firstPiece;

                    tr_bencGetInt( tr_bencListChild( b, 0 ), &offset );

                    for( i=0; i<pieces; ++i )
                    {
                        int64_t t = 0;
                        tr_bencGetInt( tr_bencListChild( b, i+1 ), &t );
                        inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0);
                    }
                }
            }
        }
        else if( tr_bencDictFindList( prog, KEY_PROGRESS_MTIMES, &l ) )
        {
            tr_file_index_t fi;

            /* Before 2.20, we stored the files' mtimes in the .resume file.
               When loading the .resume file, a torrent's file would be flagged
               as untested if its stored mtime didn't match its real mtime. */

            for( fi=0; fi<inf->fileCount; ++fi )
            {
                int64_t t;

                if( tr_bencGetInt( tr_bencListChild( l, fi ), &t ) )
                {
                    const tr_file * f = &inf->files[fi];
                    tr_piece * p = &inf->pieces[f->firstPiece];
                    const tr_piece * pend = &inf->pieces[f->lastPiece];
                    const time_t mtime = tr_torrentGetFileMTime( tor, fi );
                    const time_t timeChecked = mtime==t ? mtime : 0;

                    for( ; p!=pend; ++p )
                        p->timeChecked = timeChecked;
                }
            }
        }

        err = NULL;
        tr_bitfieldConstruct( &blocks, tor->blockCount );

        if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
        {
            size_t buflen;
            const uint8_t * buf;

            if( !tr_bencGetRaw( b, &buf, &buflen ) )
                err = "Invalid value for \"blocks\"";
            else if( ( buflen == 3 ) && !memcmp( buf, "all", 3 ) )
                tr_bitfieldSetHasAll( &blocks );
            else if( ( buflen == 4 ) && !memcmp( buf, "none", 4 ) )
                tr_bitfieldSetHasNone( &blocks );
            else
                tr_bitfieldSetRaw( &blocks, buf, buflen, true );
        }
        else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
        {
            if( !strcmp( str, "all" ) )
                tr_bitfieldSetHasAll( &blocks );
            else
                err = "Invalid value for HAVE";
        }
        else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
        {
            tr_bitfieldSetRaw( &blocks, raw, rawlen, true );
        }
        else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";

        if( err != NULL )
            tr_tordbg( tor, "Torrent needs to be verified - %s", err );
        else
            tr_cpBlockInit( &tor->completion, &blocks );

        tr_bitfieldDestruct( &blocks );
        ret = TR_FR_PROGRESS;
    }

    return ret;
}
Esempio n. 5
0
static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
{
    uint64_t ret = 0;
    tr_variant* prog;
    tr_info const* inf = tr_torrentInfo(tor);

    for (size_t i = 0; i < inf->pieceCount; ++i)
    {
        inf->pieces[i].timeChecked = 0;
    }

    if (tr_variantDictFindDict(dict, TR_KEY_progress, &prog))
    {
        char const* err;
        char const* str;
        uint8_t const* raw;
        size_t rawlen;
        tr_variant* l;
        tr_variant* b;
        struct tr_bitfield blocks = TR_BITFIELD_INIT;

        if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l))
        {
            /* per-piece timestamps were added in 2.20.

               If some of a file's pieces have been checked more recently than
               the file's mtime, and some lest recently, then that file will
               have a list containing timestamps for each piece.

               However, the most common use case is that the file doesn't change
               after it's downloaded. To reduce overhead in the .resume file,
               only a single timestamp is saved for the file if *all* or *none*
               of the pieces were tested more recently than the file's mtime. */

            for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi)
            {
                tr_variant* b = tr_variantListChild(l, fi);
                tr_file const* f = &inf->files[fi];

                if (tr_variantIsInt(b))
                {
                    int64_t t;
                    tr_variantGetInt(b, &t);

                    for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i)
                    {
                        inf->pieces[i].timeChecked = (time_t)t;
                    }
                }
                else if (tr_variantIsList(b))
                {
                    int64_t offset = 0;
                    int const pieces = f->lastPiece + 1 - f->firstPiece;

                    tr_variantGetInt(tr_variantListChild(b, 0), &offset);

                    for (int i = 0; i < pieces; ++i)
                    {
                        int64_t t = 0;
                        tr_variantGetInt(tr_variantListChild(b, i + 1), &t);
                        inf->pieces[f->firstPiece + i].timeChecked = (time_t)(t != 0 ? t + offset : 0);
                    }
                }
            }
        }
        else if (tr_variantDictFindList(prog, TR_KEY_mtimes, &l))
        {
            /* Before 2.20, we stored the files' mtimes in the .resume file.
               When loading the .resume file, a torrent's file would be flagged
               as untested if its stored mtime didn't match its real mtime. */

            for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi)
            {
                int64_t t;

                if (tr_variantGetInt(tr_variantListChild(l, fi), &t))
                {
                    tr_file const* f = &inf->files[fi];
                    time_t const mtime = tr_torrentGetFileMTime(tor, fi);
                    time_t const timeChecked = mtime == t ? mtime : 0;

                    for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i)
                    {
                        inf->pieces[i].timeChecked = timeChecked;
                    }
                }
            }
        }

        err = NULL;
        tr_bitfieldConstruct(&blocks, tor->blockCount);

        if ((b = tr_variantDictFind(prog, TR_KEY_blocks)) != NULL)
        {
            size_t buflen;
            uint8_t const* buf;

            if (!tr_variantGetRaw(b, &buf, &buflen))
            {
                err = "Invalid value for \"blocks\"";
            }
            else if (buflen == 3 && memcmp(buf, "all", 3) == 0)
            {
                tr_bitfieldSetHasAll(&blocks);
            }
            else if (buflen == 4 && memcmp(buf, "none", 4) == 0)
            {
                tr_bitfieldSetHasNone(&blocks);
            }
            else
            {
                tr_bitfieldSetRaw(&blocks, buf, buflen, true);
            }
        }
        else if (tr_variantDictFindStr(prog, TR_KEY_have, &str, NULL))
        {
            if (strcmp(str, "all") == 0)
            {
                tr_bitfieldSetHasAll(&blocks);
            }
            else
            {
                err = "Invalid value for HAVE";
            }
        }
        else if (tr_variantDictFindRaw(prog, TR_KEY_bitfield, &raw, &rawlen))
        {
            tr_bitfieldSetRaw(&blocks, raw, rawlen, true);
        }
        else
        {
            err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
        }

        if (err != NULL)
        {
            tr_logAddTorDbg(tor, "Torrent needs to be verified - %s", err);
        }
        else
        {
            tr_cpBlockInit(&tor->completion, &blocks);
        }

        tr_bitfieldDestruct(&blocks);
        ret = TR_FR_PROGRESS;
    }

    return ret;
}