static uint64_t loadSpeedLimits( tr_benc * dict, tr_torrent * tor ) { tr_benc * d; uint64_t ret = 0; if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_UP, &d ) ) { loadSingleSpeedLimit( d, TR_UP, tor ); ret = TR_FR_SPEEDLIMIT; } if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_DOWN, &d ) ) { loadSingleSpeedLimit( d, TR_DOWN, tor ); ret = TR_FR_SPEEDLIMIT; } /* older speedlimit structure */ if( !ret && tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_OLD, &d ) ) { int64_t i; if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) ) tr_torrentSetSpeedLimit_Bps( tor, TR_DOWN, i*1024 ); if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) ) { tr_torrentUseSpeedLimit( tor, TR_DOWN, i==TR_SPEEDLIMIT_SINGLE ); tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL ); } if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) ) tr_torrentSetSpeedLimit_Bps( tor, TR_UP, i*1024 ); if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) ) { tr_torrentUseSpeedLimit( tor, TR_UP, i==TR_SPEEDLIMIT_SINGLE ); tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL ); } ret = TR_FR_SPEEDLIMIT; } return ret; }
static uint64_t loadIdleLimits( tr_benc * dict, tr_torrent * tor ) { tr_benc * d; uint64_t ret = 0; if( tr_bencDictFindDict( dict, KEY_IDLELIMIT, &d ) ) { int64_t i; int64_t imin; if( tr_bencDictFindInt( d, KEY_IDLELIMIT_MINS, &imin ) ) tr_torrentSetIdleLimit( tor, imin ); if( tr_bencDictFindInt( d, KEY_IDLELIMIT_MODE, &i ) ) tr_torrentSetIdleMode( tor, i ); ret = TR_FR_IDLELIMIT; } return ret; }
static uint64_t loadRatioLimits( tr_benc * dict, tr_torrent * tor ) { tr_benc * d; uint64_t ret = 0; if( tr_bencDictFindDict( dict, KEY_RATIOLIMIT, &d ) ) { int64_t i; double dratio; if( tr_bencDictFindReal( d, KEY_RATIOLIMIT_RATIO, &dratio ) ) tr_torrentSetRatioLimit( tor, dratio ); if( tr_bencDictFindInt( d, KEY_RATIOLIMIT_MODE, &i ) ) tr_torrentSetRatioMode( tor, i ); ret = TR_FR_RATIOLIMIT; } return ret; }
int tr_ctorSetMetainfoFromFile( tr_ctor * ctor, const char * filename ) { uint8_t * metainfo; size_t len; int err; metainfo = tr_loadFile( filename, &len ); if( metainfo && len ) err = tr_ctorSetMetainfo( ctor, metainfo, len ); else { clearMetainfo( ctor ); err = 1; } setSourceFile( ctor, filename ); /* if no `name' field was set, then set it from the filename */ if( ctor->isSet_metainfo ) { tr_benc * info; if( tr_bencDictFindDict( &ctor->metainfo, "info", &info ) ) { const char * name; if( !tr_bencDictFindStr( info, "name.utf-8", &name ) ) if( !tr_bencDictFindStr( info, "name", &name ) ) name = NULL; if( !name || !*name ) { char * base = tr_basename( filename ); tr_bencDictAddStr( info, "name", base ); tr_free( base ); } } } tr_free( metainfo ); return err; }
static uint64_t loadSpeedLimits( tr_benc * dict, tr_torrent * tor ) { uint64_t ret = 0; tr_benc * d; if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT, &d ) ) { int64_t i; if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) ) tr_torrentSetSpeedLimit( tor, TR_DOWN, i ); if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) ) tr_torrentSetSpeedMode( tor, TR_DOWN, i ); if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) ) tr_torrentSetSpeedLimit( tor, TR_UP, i ); if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) ) tr_torrentSetSpeedMode( tor, TR_UP, i ); ret = TR_FR_SPEEDLIMIT; } return ret; }
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_bitset bitset = TR_BITSET_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; 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_bitsetSetHaveAll( &bitset ); else err = "Invalid value for HAVE"; } else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) ) { bitset.bitfield.bits = (void*) raw; bitset.bitfield.byteCount = rawlen; bitset.bitfield.bitCount = rawlen * 8; } 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 ); ret = TR_FR_PROGRESS; } return ret; }
static void on_scrape_done( tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata ) { tr_scrape_response * response; struct scrape_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg( data->log_name, "Got scrape response for \"%s\"", response->url ); if( response_code != HTTP_OK ) { const char * fmt = _( "Tracker gave HTTP response code %1$ld (%2$s)" ); const char * response_str = tr_webGetResponseStr( response_code ); response->errmsg = tr_strdup_printf( fmt, response_code, response_str ); } else { tr_benc top; int64_t intVal; tr_benc * files; const char * str; const int benc_loaded = !tr_bencLoad( msg, msglen, &top, NULL ); if( benc_loaded ) { if( tr_bencDictFindStr( &top, "failure reason", &str ) ) response->errmsg = tr_strdup( str ); if( tr_bencDictFindInt( &top, "min_request_interval", &intVal ) ) response->min_request_interval = intVal; if( tr_bencDictFindDict( &top, "files", &files ) ) { int i = 0; for( ;; ) { int j; tr_benc * val; const char * key; /* get the next "file" */ if( !tr_bencDictChild( files, i++, &key, &val ) ) break; /* populate the corresponding row in our response array */ for( j=0; j<response->row_count; ++j ) { struct tr_scrape_response_row * row = &response->rows[j]; if( !memcmp( key, row->info_hash, SHA_DIGEST_LENGTH ) ) { if( tr_bencDictFindInt( val, "complete", &intVal ) ) row->seeders = intVal; if( tr_bencDictFindInt( val, "incomplete", &intVal ) ) row->leechers = intVal; if( tr_bencDictFindInt( val, "downloaded", &intVal ) ) row->downloads = intVal; if( tr_bencDictFindInt( val, "downloaders", &intVal ) ) row->downloaders = intVal; break; } } } } tr_bencFree( &top ); } } tr_runInEventThread( session, on_scrape_done_eventthread, data ); }
static uint64_t loadProgress( tr_benc * dict, tr_torrent * tor ) { uint64_t ret = 0; tr_benc * p; if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) ) { const uint8_t * raw; size_t rawlen; tr_benc * m; size_t n; time_t * curMTimes = tr_torrentGetMTimes( tor, &n ); if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m ) && ( n == tor->info.fileCount ) && ( n == tr_bencListSize( m ) ) ) { size_t i; for( i = 0; i < n; ++i ) { int64_t tmp; if( !tr_bencGetInt( tr_bencListChild( m, i ), &tmp ) ) { tr_tordbg( tor, "File #%zu needs to be verified - couldn't find benc entry", i ); tr_torrentSetFileChecked( tor, i, FALSE ); } else { const time_t t = (time_t) tmp; if( t == curMTimes[i] ) tr_torrentSetFileChecked( tor, i, TRUE ); else { tr_tordbg( tor, "File #%zu needs to be verified - times %lu and %lu don't match", i, t, curMTimes[i] ); tr_torrentSetFileChecked( tor, i, FALSE ); } } } } else { tr_torrentUncheck( tor ); tr_tordbg( tor, "Torrent needs to be verified - unable to find mtimes" ); } if( tr_bencDictFindRaw( p, 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 ) ) { tr_torrentUncheck( tor ); tr_tordbg( tor, "Torrent needs to be verified - error loading bitfield" ); } } else { tr_torrentUncheck( tor ); tr_tordbg( tor, "Torrent needs to be verified - unable to find bitfield" ); } tr_free( curMTimes ); ret = TR_FR_PROGRESS; } return ret; }