From 36d97610bde962c10bab53d627015802c37ce1fe Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 2 Feb 2010 22:45:22 +0000 Subject: [PATCH] (trunk) #2802, #2716, #2717 -- remember magnet links and their settings between sessions, and allow their trackers to be modified --- cli/cli.c | 2 +- gtk/tr-core.c | 2 +- libtransmission/bencode.c | 126 +++++++++++++++++++---- libtransmission/bencode.h | 6 ++ libtransmission/magnet.c | 33 ++++++ libtransmission/magnet.h | 4 + libtransmission/metainfo.c | 166 +++++++++++++++---------------- libtransmission/metainfo.h | 8 +- libtransmission/resume.c | 9 +- libtransmission/rpcimpl.c | 2 +- libtransmission/torrent-ctor.c | 35 +++---- libtransmission/torrent-magnet.c | 81 +++++++-------- libtransmission/torrent.c | 63 +++++------- libtransmission/torrent.h | 2 - libtransmission/transmission.h | 4 +- macosx/Torrent.m | 2 +- 16 files changed, 324 insertions(+), 221 deletions(-) diff --git a/cli/cli.c b/cli/cli.c index 326223769..a4505bf78 100644 --- a/cli/cli.c +++ b/cli/cli.c @@ -381,7 +381,7 @@ main( int argc, if( fileContents != NULL ) { tr_ctorSetMetainfo( ctor, fileContents, fileLength ); } else if( !memcmp( torrentPath, "magnet:?", 8 ) ) { - tr_ctorSetMagnet( ctor, torrentPath ); + tr_ctorSetMetainfoFromMagnetLink( ctor, torrentPath ); } else if( !memcmp( torrentPath, "http", 4 ) ) { tr_webRun( h, torrentPath, NULL, onTorrentFileDownloaded, ctor ); waitingOnWeb = TRUE; diff --git a/gtk/tr-core.c b/gtk/tr-core.c index e9c12845b..0b2948eb3 100644 --- a/gtk/tr-core.c +++ b/gtk/tr-core.c @@ -1052,7 +1052,7 @@ tr_core_add_from_url( TrCore * core, const char * url ) if( gtr_is_hex_hashcode( url ) ) url = tmp = g_strdup_printf( "magnet:?xt=urn:btih:%s", url ); - err = tr_ctorSetMagnet( ctor, url ); + err = tr_ctorSetMetainfoFromMagnetLink( ctor, url ); if( !err ) { diff --git a/libtransmission/bencode.c b/libtransmission/bencode.c index b0e9d73a5..2c0bcdd8f 100644 --- a/libtransmission/bencode.c +++ b/libtransmission/bencode.c @@ -671,8 +671,7 @@ tr_bencListAdd( tr_benc * list ) } tr_benc * -tr_bencListAddInt( tr_benc * list, - int64_t val ) +tr_bencListAddInt( tr_benc * list, int64_t val ) { tr_benc * node = tr_bencListAdd( list ); @@ -681,15 +680,37 @@ tr_bencListAddInt( tr_benc * list, } tr_benc * -tr_bencListAddStr( tr_benc * list, - const char * val ) +tr_bencListAddReal( tr_benc * list, double val ) { tr_benc * node = tr_bencListAdd( list ); + tr_bencInitReal( node, val ); + return node; +} +tr_benc * +tr_bencListAddBool( tr_benc * list, tr_bool val ) +{ + tr_benc * node = tr_bencListAdd( list ); + tr_bencInitBool( node, val ); + return node; +} + +tr_benc * +tr_bencListAddStr( tr_benc * list, const char * val ) +{ + tr_benc * node = tr_bencListAdd( list ); tr_bencInitStr( node, val, -1 ); return node; } +tr_benc * +tr_bencListAddRaw( tr_benc * list, const uint8_t * val, size_t len ) +{ + tr_benc * node = tr_bencListAdd( list ); + tr_bencInitRaw( node, val, len ); + return node; +} + tr_benc* tr_bencListAddList( tr_benc * list, size_t reserveCount ) @@ -803,36 +824,53 @@ tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val ) } tr_benc* -tr_bencDictAddList( tr_benc * dict, - const char * key, - size_t reserveCount ) +tr_bencDictAddRaw( tr_benc * dict, + const char * key, + const void * src, + size_t len ) { - tr_benc * child = tr_bencDictAdd( dict, key ); + tr_benc * child; + + /* see if it already exists, and if so, try to reuse it */ + if(( child = tr_bencDictFind( dict, key ))) { + if( tr_bencIsString( child ) ) { + if( stringIsAlloced( child ) ) + tr_free( child->val.s.str.ptr ); + } else { + tr_bencDictRemove( dict, key ); + child = NULL; + } + } + + /* if it doesn't exist, create it */ + if( child == NULL ) + child = tr_bencDictAdd( dict, key ); + + /* set it */ + tr_bencInitRaw( child, src, len ); - tr_bencInitList( child, reserveCount ); return child; } tr_benc* -tr_bencDictAddDict( tr_benc * dict, +tr_bencDictAddList( tr_benc * dict, const char * key, size_t reserveCount ) { tr_benc * child = tr_bencDictAdd( dict, key ); - tr_bencInitDict( child, reserveCount ); + tr_bencInitList( child, reserveCount ); return child; } tr_benc* -tr_bencDictAddRaw( tr_benc * dict, - const char * key, - const void * src, - size_t len ) +tr_bencDictAddDict( tr_benc * dict, + const char * key, + size_t reserveCount ) { tr_benc * child = tr_bencDictAdd( dict, key ); - tr_bencInitRaw( child, src, len ); + tr_bencInitDict( child, reserveCount ); return child; } @@ -1404,6 +1442,51 @@ static const struct WalkFuncs jsonWalkFuncs = { jsonIntFunc, **** ***/ +static void +tr_bencListCopy( tr_benc * target, const tr_benc * src ) +{ + int i = 0; + const tr_benc * val; + + while(( val = tr_bencListChild( (tr_benc*)src, i++ ))) + { + if( tr_bencIsBool( val ) ) + { + tr_bool boolVal = 0; + tr_bencGetBool( val, &boolVal ); + tr_bencListAddBool( target, boolVal ); + } + else if( tr_bencIsReal( val ) ) + { + double realVal = 0; + tr_bencGetReal( val, &realVal ); + tr_bencListAddReal( target, realVal ); + } + else if( tr_bencIsInt( val ) ) + { + int64_t intVal = 0; + tr_bencGetInt( val, &intVal ); + tr_bencListAddInt( target, intVal ); + } + else if( tr_bencIsString( val ) ) + { + tr_bencListAddRaw( target, (const uint8_t*)getStr( val ), val->val.s.len ); + } + else if( tr_bencIsDict( val ) ) + { + tr_bencMergeDicts( tr_bencListAddDict( target, 0 ), val ); + } + else if ( tr_bencIsList( val ) ) + { + tr_bencListCopy( tr_bencListAddList( target, 0 ), val ); + } + else + { + tr_err( "tr_bencListCopy skipping item" ); + } + } +} + static size_t tr_bencDictSize( const tr_benc * dict ) { @@ -1470,14 +1553,19 @@ tr_bencMergeDicts( tr_benc * target, const tr_benc * source ) } else if( tr_bencIsString( val ) ) { - const char * strVal = NULL; - tr_bencGetStr( val, &strVal ); - tr_bencDictAddStr( target, key, strVal ); + tr_bencDictAddRaw( target, key, getStr( val ), val->val.s.len ); } else if( tr_bencIsDict( val ) && tr_bencDictFindDict( target, key, &t ) ) { tr_bencMergeDicts( t, val ); } + else if( tr_bencIsList( val ) ) + { + if( tr_bencDictFind( target, key ) == NULL ) + { + tr_bencListCopy( tr_bencDictAddList( target, key, tr_bencListSize( val ) ), val ); + } + } else { tr_dbg( "tr_bencMergeDicts skipping \"%s\"", key ); diff --git a/libtransmission/bencode.h b/libtransmission/bencode.h index 62cea688c..c69ddd8f5 100644 --- a/libtransmission/bencode.h +++ b/libtransmission/bencode.h @@ -138,10 +138,16 @@ int tr_bencListReserve( tr_benc *, size_t reserveCount ); tr_benc * tr_bencListAdd( tr_benc * ); +tr_benc * tr_bencListAddBool( tr_benc *, tr_bool val ); + tr_benc * tr_bencListAddInt( tr_benc *, int64_t val ); +tr_benc * tr_bencListAddReal( tr_benc *, double val ); + tr_benc * tr_bencListAddStr( tr_benc *, const char * val ); +tr_benc * tr_bencListAddRaw( tr_benc *, const uint8_t * val, size_t len ); + tr_benc * tr_bencListAddList( tr_benc *, size_t reserveCount ); tr_benc * tr_bencListAddDict( tr_benc *, size_t reserveCount ); diff --git a/libtransmission/magnet.c b/libtransmission/magnet.c index 1851a144e..6ccd9191f 100644 --- a/libtransmission/magnet.c +++ b/libtransmission/magnet.c @@ -14,6 +14,7 @@ #include /* strchr() */ #include "transmission.h" +#include "bencode.h" #include "magnet.h" #include "utils.h" #include "web.h" @@ -193,3 +194,35 @@ tr_magnetFree( tr_magnet_info * info ) tr_free( info ); } } + +void +tr_magnetCreateMetainfo( const tr_magnet_info * info, tr_benc * top ) +{ + int i; + tr_benc * d; + tr_bencInitDict( top, 4 ); + + /* announce list */ + if( info->trackerCount == 1 ) + tr_bencDictAddStr( top, "announce", info->trackers[0] ); + else { + tr_benc * trackers = tr_bencDictAddList( top, "announce-list", info->trackerCount ); + for( i=0; itrackerCount; ++i ) + tr_bencListAddStr( tr_bencListAddList( trackers, 1 ), info->trackers[i] ); + } + + /* webseeds */ + if( info->webseedCount > 0 ) { + tr_benc * urls = tr_bencDictAddList( top, "url-list", info->webseedCount ); + for( i=0; iwebseedCount; ++i ) + tr_bencListAddStr( urls, info->webseeds[i] ); + } + + /* nonstandard keys */ + d = tr_bencDictAddDict( top, "magnet-info", 2 ); + tr_bencDictAddRaw( d, "info_hash", info->hash, 20 ); + if( info->displayName != NULL ) + tr_bencDictAddStr( d, "display-name", info->displayName ); +} + + diff --git a/libtransmission/magnet.h b/libtransmission/magnet.h index c03481c90..ef9ddcdd4 100644 --- a/libtransmission/magnet.h +++ b/libtransmission/magnet.h @@ -35,6 +35,10 @@ tr_magnet_info; tr_magnet_info * tr_magnetParse( const char * uri ); +struct tr_benc; + +void tr_magnetCreateMetainfo( const tr_magnet_info *, struct tr_benc * ); + void tr_magnetFree( tr_magnet_info * info ); #endif diff --git a/libtransmission/metainfo.c b/libtransmission/metainfo.c index b1b06ba1c..c3cac5d1c 100644 --- a/libtransmission/metainfo.c +++ b/libtransmission/metainfo.c @@ -26,7 +26,6 @@ #include "session.h" #include "bencode.h" #include "crypto.h" /* tr_sha1 */ -#include "magnet.h" #include "metainfo.h" #include "platform.h" #include "utils.h" @@ -384,29 +383,61 @@ escape( char * out, const uint8_t * in, size_t in_len ) /* rfc2396 */ } static const char* -tr_metainfoParseImpl( const tr_session * session, - tr_info * inf, - int * infoDictOffset, - int * infoDictLength, - const tr_benc * meta_in ) +tr_metainfoParseImpl( const tr_session * session, + tr_info * inf, + tr_bool * hasInfoDict, + int * infoDictOffset, + int * infoDictLength, + const tr_benc * meta_in ) { int64_t i; size_t raw_len; const char * str; const uint8_t * raw; - tr_benc * beInfo; + tr_benc * d; + tr_benc * infoDict = NULL; tr_benc * meta = (tr_benc *) meta_in; tr_bool err; + tr_bool b; + tr_bool isMagnet = FALSE; /* info_hash: urlencoded 20-byte SHA1 hash of the value of the info key * from the Metainfo file. Note that the value will be a bencoded * dictionary, given the definition of the info key above. */ - if( !tr_bencDictFindDict( meta, "info", &beInfo ) ) - return "info"; + b = tr_bencDictFindDict( meta, "info", &infoDict ); + if( hasInfoDict != NULL ) + *hasInfoDict = b; + if( !b ) + { + /* no info dictionary... is this a magnet link? */ + if( tr_bencDictFindDict( meta, "magnet-info", &d ) ) + { + isMagnet = TRUE; + + /* get the info-hash */ + if( !tr_bencDictFindRaw( d, "info_hash", &raw, &raw_len ) ) + return "info_hash"; + if( raw_len != SHA_DIGEST_LENGTH ) + return "info_hash"; + memcpy( inf->hash, raw, raw_len ); + tr_sha1_to_hex( inf->hashString, inf->hash ); + escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH ); + + /* maybe get the display name */ + if( tr_bencDictFindStr( d, "display-name", &str ) ) { + tr_free( inf->name ); + inf->name = tr_strdup( str ); + } + } + else /* not a magnet link and has no info dict... */ + { + return "info"; + } + } else { int len; - char * bstr = tr_bencToStr( beInfo, TR_FMT_BENC, &len ); + char * bstr = tr_bencToStr( infoDict, TR_FMT_BENC, &len ); tr_sha1( inf->hash, bstr, len, NULL ); tr_sha1_to_hex( inf->hashString, inf->hash ); escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH ); @@ -430,13 +461,15 @@ tr_metainfoParseImpl( const tr_session * session, } /* name */ - if( !tr_bencDictFindStr( beInfo, "name.utf-8", &str ) ) - if( !tr_bencDictFindStr( beInfo, "name", &str ) ) - str = ""; - if( !str || !*str ) - return "name"; - tr_free( inf->name ); - inf->name = tr_utf8clean( str, -1, &err ); + if( !isMagnet ) { + if( !tr_bencDictFindStr( infoDict, "name.utf-8", &str ) ) + if( !tr_bencDictFindStr( infoDict, "name", &str ) ) + str = ""; + if( !str || !*str ) + return "name"; + tr_free( inf->name ); + inf->name = tr_utf8clean( str, -1, &err ); + } /* comment */ if( !tr_bencDictFindStr( meta, "comment.utf-8", &str ) ) @@ -458,35 +491,42 @@ tr_metainfoParseImpl( const tr_session * session, inf->dateCreated = i; /* private */ - if( !tr_bencDictFindInt( beInfo, "private", &i ) ) + if( !tr_bencDictFindInt( infoDict, "private", &i ) ) if( !tr_bencDictFindInt( meta, "private", &i ) ) i = 0; inf->isPrivate = i != 0; /* piece length */ - if( !tr_bencDictFindInt( beInfo, "piece length", &i ) || ( i < 1 ) ) - return "piece length"; - inf->pieceSize = i; + if( !isMagnet ) { + if( !tr_bencDictFindInt( infoDict, "piece length", &i ) || ( i < 1 ) ) + return "piece length"; + inf->pieceSize = i; + } /* pieces */ - if( !tr_bencDictFindRaw( beInfo, "pieces", &raw, - &raw_len ) || ( raw_len % SHA_DIGEST_LENGTH ) ) - return "pieces"; - inf->pieceCount = raw_len / SHA_DIGEST_LENGTH; - inf->pieces = tr_new0( tr_piece, inf->pieceCount ); - for( i = 0; i < inf->pieceCount; ++i ) - memcpy( inf->pieces[i].hash, &raw[i * SHA_DIGEST_LENGTH], - SHA_DIGEST_LENGTH ); + if( !isMagnet ) { + if( !tr_bencDictFindRaw( infoDict, "pieces", &raw, &raw_len ) ) + return "pieces"; + if( raw_len % SHA_DIGEST_LENGTH ) + return "pieces"; + inf->pieceCount = raw_len / SHA_DIGEST_LENGTH; + inf->pieces = tr_new0( tr_piece, inf->pieceCount ); + for( i = 0; i < inf->pieceCount; ++i ) + memcpy( inf->pieces[i].hash, &raw[i * SHA_DIGEST_LENGTH], + SHA_DIGEST_LENGTH ); + } /* files */ - if( ( str = parseFiles( inf, tr_bencDictFind( beInfo, "files" ), - tr_bencDictFind( beInfo, "length" ) ) ) ) - return str; - if( !inf->fileCount || !inf->totalSize ) - return "files"; - if( (uint64_t) inf->pieceCount != - ( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize ) - return "files"; + if( !isMagnet ) { + if( ( str = parseFiles( inf, tr_bencDictFind( infoDict, "files" ), + tr_bencDictFind( infoDict, "length" ) ) ) ) + return str; + if( !inf->fileCount || !inf->totalSize ) + return "files"; + if( (uint64_t) inf->pieceCount != + ( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize ) + return "files"; + } /* get announce or announce-list */ if( ( str = getannounce( inf, meta ) ) ) @@ -504,13 +544,15 @@ tr_metainfoParseImpl( const tr_session * session, tr_bool tr_metainfoParse( const tr_session * session, + const tr_benc * meta_in, tr_info * inf, + tr_bool * hasInfoDict, int * infoDictOffset, - int * infoDictLength, - const tr_benc * meta_in ) + int * infoDictLength ) { const char * badTag = tr_metainfoParseImpl( session, inf, + hasInfoDict, infoDictOffset, infoDictLength, meta_in ); @@ -569,49 +611,3 @@ tr_metainfoRemoveSaved( const tr_session * session, unlink( filename ); tr_free( filename ); } - -/*** -**** -***/ - -void -tr_metainfoSetFromMagnet( tr_info * inf, const tr_magnet_info * m ) -{ - /* hash */ - memcpy( inf->hash, m->hash, 20 ); - tr_sha1_to_hex( inf->hashString, inf->hash ); - escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH ); - - /* name */ - if( m->displayName && *m->displayName ) - inf->name = tr_strdup( m->displayName ); - else - inf->name = tr_strdup( inf->hashString ); - - /* trackers */ - if(( inf->trackerCount = m->trackerCount )) - { - int i; - const int n = m->trackerCount; - - inf->trackers = tr_new0( tr_tracker_info, n ); - for( i=0; itrackers[i]; - inf->trackers[i].tier = i; - inf->trackers[i].announce = tr_strdup( url ); - inf->trackers[i].scrape = tr_convertAnnounceToScrape( url ); - inf->trackers[i].id = i; - } - } - - /* webseeds */ - if(( inf->webseedCount = m->webseedCount )) - { - int i; - const int n = m->webseedCount; - - inf->webseeds = tr_new0( char*, n ); - for( i=0; iwebseeds[i] = tr_strdup( m->webseeds[i] ); - } -} diff --git a/libtransmission/metainfo.h b/libtransmission/metainfo.h index 79fec46e6..f9273f131 100644 --- a/libtransmission/metainfo.h +++ b/libtransmission/metainfo.h @@ -20,13 +20,13 @@ #include "transmission.h" struct tr_benc; -struct tr_magnet_info; tr_bool tr_metainfoParse( const tr_session * session, + const struct tr_benc * benc, tr_info * setmeInfo, + tr_bool * setmeHasInfoDict, int * setmeInfoDictOffset, - int * setmeInfoDictLength, - const struct tr_benc * benc ); + int * setmeInfoDictLength ); void tr_metainfoRemoveSaved( const tr_session * session, const tr_info * info ); @@ -34,7 +34,5 @@ void tr_metainfoRemoveSaved( const tr_session * session, void tr_metainfoMigrate( tr_session * session, tr_info * inf ); -void tr_metainfoSetFromMagnet( tr_info * inf, const struct tr_magnet_info * m ); - #endif diff --git a/libtransmission/resume.c b/libtransmission/resume.c index 3fa54046c..ddfb17689 100644 --- a/libtransmission/resume.c +++ b/libtransmission/resume.c @@ -517,9 +517,12 @@ tr_torrentSaveResume( const tr_torrent * tor ) tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) ); tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning ); savePeers( &top, tor ); - saveFilePriorities( &top, tor ); - saveDND( &top, tor ); - saveProgress( &top, tor ); + if( tr_torrentHasMetadata( tor ) ) + { + saveFilePriorities( &top, tor ); + saveDND( &top, tor ); + saveProgress( &top, tor ); + } saveSpeedLimits( &top, tor ); saveRatioLimits( &top, tor ); diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index cb54f0b01..2dc8f5169 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -1118,7 +1118,7 @@ torrentAdd( tr_session * session, } else if( !strncmp( fname, "magnet:?", 8 ) ) { - tr_ctorSetMagnet( ctor, fname ); + tr_ctorSetMetainfoFromMagnetLink( ctor, fname ); } else { diff --git a/libtransmission/torrent-ctor.c b/libtransmission/torrent-ctor.c index 299e1320a..471a5860a 100644 --- a/libtransmission/torrent-ctor.c +++ b/libtransmission/torrent-ctor.c @@ -44,8 +44,6 @@ struct tr_ctor tr_benc metainfo; char * sourceFile; - tr_magnet_info * magnetInfo; - struct optional_args optionalArgs[2]; char * incompleteDir; @@ -106,16 +104,26 @@ tr_ctorGetSourceFile( const tr_ctor * ctor ) } int -tr_ctorSetMagnet( tr_ctor * ctor, const char * uri ) +tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link ) { int err; + tr_magnet_info * magnet_info = tr_magnetParse( magnet_link ); + + if( magnet_info == NULL ) + err = -1; + else { + int len; + tr_benc tmp; + char * str; - if( ctor->magnetInfo != NULL ) - tr_magnetFree( ctor->magnetInfo ); + tr_magnetCreateMetainfo( magnet_info, &tmp ); + str = tr_bencToStr( &tmp, TR_FMT_BENC, &len ); + err = tr_ctorSetMetainfo( ctor, (const uint8_t*)str, len ); - ctor->magnetInfo = tr_magnetParse( uri ); + tr_free( str ); + tr_magnetFree( magnet_info ); + } - err = ctor->magnetInfo == NULL; return err; } @@ -389,19 +397,6 @@ tr_ctorGetIncompleteDir( const tr_ctor * ctor, return err; } -int -tr_ctorGetMagnet( const tr_ctor * ctor, const tr_magnet_info ** setme ) -{ - int err = 0; - - if( ctor->magnetInfo == NULL ) - err = 1; - else - *setme = ctor->magnetInfo; - - return err; -} - int tr_ctorGetMetainfo( const tr_ctor * ctor, const tr_benc ** setme ) diff --git a/libtransmission/torrent-magnet.c b/libtransmission/torrent-magnet.c index d6b2c7c93..1b7a977a3 100644 --- a/libtransmission/torrent-magnet.c +++ b/libtransmission/torrent-magnet.c @@ -138,10 +138,7 @@ tr_torrentGetMetadataPiece( const tr_torrent * tor, int piece, int * len ) } void -tr_torrentSetMetadataPiece( tr_torrent * tor, - int piece, - const void * data, - int len ) +tr_torrentSetMetadataPiece( tr_torrent * tor, int piece, const void * data, int len ) { int i; struct tr_incomplete_metadata * m; @@ -179,58 +176,48 @@ tr_torrentSetMetadataPiece( tr_torrent * tor, if( m->piecesNeededCount == 0 ) { tr_bool success = FALSE; + tr_bool checksumPassed = FALSE; + tr_bool metainfoParsed = FALSE; uint8_t sha1[SHA_DIGEST_LENGTH]; + + /* we've got a complete set of metainfo... see if it passes the checksum test */ dbgmsg( tor, "metainfo piece %d was the last one", piece ); tr_sha1( sha1, m->metadata, m->metadata_size, NULL ); - if( !memcmp( sha1, tor->info.hash, SHA_DIGEST_LENGTH ) ) + if(( checksumPassed = !memcmp( sha1, tor->info.hash, SHA_DIGEST_LENGTH ))) { - int err; - tr_benc dict; - struct evbuffer * buf = evbuffer_new( ); - dbgmsg( tor, "metadata checksum passed! (length: %d)", (int)m->metadata_size ); - - /* add a wrapper dictionary to the benc. - * include the announce-list too, - * so we can save it in the .torrent for future sessions */ - evbuffer_add_printf( buf, "d" ); - evbuffer_add_printf( buf, "13:announce-list" ); - evbuffer_add_printf( buf, "l" ); - for( i=0; iinfo.trackerCount; ++i ) { - const char * url = tor->info.trackers[i].announce; - evbuffer_add_printf( buf, "l%zu:%se", strlen( url ), url ); - } - evbuffer_add_printf( buf, "e" ); - evbuffer_add_printf( buf, "4:info" ); - evbuffer_add( buf, m->metadata, m->metadata_size ); - evbuffer_add_printf( buf, "e" ); - - /* does it parse? */ - err = tr_bencLoad( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ), &dict, NULL ); + /* checksum passed; now try to parse it as benc */ + tr_benc infoDict; + const int err = tr_bencLoad( m->metadata, m->metadata_size, &infoDict, NULL ); dbgmsg( tor, "err is %d", err ); - if( !err ) + if(( metainfoParsed = !err )) { - if( tr_metainfoParse( tor->session, - &tor->info, - &tor->infoDictOffset, - &tor->infoDictLength, - &dict ) ) + /* yay we have bencoded metainfo... merge it into our .torrnet file */ + tr_benc newMetainfo; + const char * path = tor->info.torrent; + if( !tr_bencLoadFile( &newMetainfo, TR_FMT_BENC, path ) ) { - const char * path = tor->info.torrent; - dbgmsg( tor, "saving completed metadata to \"%s\"", path ); + tr_bool hasInfo; + tr_benc * tmp; - success = TRUE; - tr_torrentGotNewInfoDict( tor ); + dbgmsg( tor, "Saving completed metadata to \"%s\"", path ); + assert( !tr_bencDictFindDict( &newMetainfo, "info", &tmp ) ); + tr_bencMergeDicts( tr_bencDictAddDict( &newMetainfo, "info", 0 ), &infoDict ); + tr_bencToFile( &newMetainfo, TR_FMT_BENC, path ); - tr_bencToFile( &dict, TR_FMT_BENC, path ); - tr_sessionSetTorrentFile( tor->session, - tor->info.hashString, path ); + success = tr_metainfoParse( tor->session, &newMetainfo, &tor->info, + &hasInfo, &tor->infoDictOffset, &tor->infoDictLength ); + + assert( hasInfo ); + assert( success ); + + tr_torrentGotNewInfoDict( tor ); tr_torrentSetDirty( tor ); - } - tr_bencFree( &dict ); + tr_bencFree( &newMetainfo ); + } + + tr_bencFree( &infoDict ); } - - evbuffer_free( buf ); } if( success ) @@ -241,12 +228,16 @@ tr_torrentSetMetadataPiece( tr_torrent * tor, else /* drat. */ { const int n = m->pieceCount; - for( i=0; ipiecesNeeded[i].piece = i; m->piecesNeeded[i].requestedAt = 0; } m->piecesNeededCount = n; dbgmsg( tor, "metadata error; trying again. %d pieces left", n ); + + tr_err( "magnet status: checksum passed %d, metainfo parsed %d", + (int)checksumPassed, (int)metainfoParsed ); } } } diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index 1aab17ee9..a808e2f0e 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -712,10 +712,11 @@ torrentInit( tr_torrent * tor, const tr_ctor * ctor ) static tr_parse_result torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo, - int * dictOffset, int * dictLength ) + tr_bool * setmeHasInfo, int * dictOffset, int * dictLength ) { int doFree; tr_bool didParse; + tr_bool hasInfo = FALSE; tr_info tmp; const tr_benc * metainfo; tr_session * session = tr_ctorGetSession( ctor ); @@ -728,13 +729,14 @@ torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo, if( tr_ctorGetMetainfo( ctor, &metainfo ) ) return TR_PARSE_ERR; - didParse = tr_metainfoParse( session, setmeInfo, dictOffset, dictLength, metainfo ); + didParse = tr_metainfoParse( session, metainfo, setmeInfo, + &hasInfo, dictOffset, dictLength ); doFree = didParse && ( setmeInfo == &tmp ); if( !didParse ) result = TR_PARSE_ERR; - if( didParse && !getBlockSize( setmeInfo->pieceSize ) ) + if( didParse && hasInfo && !getBlockSize( setmeInfo->pieceSize ) ) result = TR_PARSE_ERR; if( didParse && session && tr_torrentExists( session, setmeInfo->hash ) ) @@ -743,56 +745,46 @@ torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo, if( doFree ) tr_metainfoFree( setmeInfo ); + if( setmeHasInfo != NULL ) + *setmeHasInfo = hasInfo; + return result; } tr_parse_result tr_torrentParse( const tr_ctor * ctor, tr_info * setmeInfo ) { - return torrentParseImpl( ctor, setmeInfo, NULL, NULL ); + return torrentParseImpl( ctor, setmeInfo, NULL, NULL, NULL ); } tr_torrent * tr_torrentNew( const tr_ctor * ctor, int * setmeError ) { + int off, len; + tr_bool hasInfo; tr_info tmpInfo; + tr_parse_result r; tr_torrent * tor = NULL; - const tr_magnet_info * magnetInfo; tr_session * session = tr_ctorGetSession( ctor ); assert( ctor != NULL ); assert( tr_isSession( session ) ); - if( !tr_ctorGetMagnet( ctor, &magnetInfo ) ) + r = torrentParseImpl( ctor, &tmpInfo, &hasInfo, &off, &len ); + if( r == TR_PARSE_OK ) { - if( tr_torrentFindFromHash( session, magnetInfo->hash ) != NULL ) - { - if( setmeError ) - *setmeError = TR_PARSE_DUPLICATE; - } - else + tor = tr_new0( tr_torrent, 1 ); + tor->info = tmpInfo; + if( hasInfo ) { - tor = tr_new0( tr_torrent, 1 ); - tr_metainfoSetFromMagnet( &tor->info, magnetInfo ); - torrentInit( tor, ctor ); - } - } - else - { - int off, len; - tr_parse_result r = torrentParseImpl( ctor, &tmpInfo, &off, &len ); - if( r == TR_PARSE_OK ) - { - tor = tr_new0( tr_torrent, 1 ); - tor->info = tmpInfo; tor->infoDictOffset = off; tor->infoDictLength = len; - torrentInit( tor, ctor ); - } - else if( setmeError ) - { - *setmeError = r; } + torrentInit( tor, ctor ); + } + else if( setmeError ) + { + *setmeError = r; } return tor; @@ -1469,7 +1461,7 @@ tr_torrentSave( tr_torrent * tor ) { assert( tr_isTorrent( tor ) ); - if( tor->isDirty && tr_torrentHasMetadata( tor ) ) + if( tor->isDirty ) { tor->isDirty = FALSE; tr_torrentSaveResume( tor ); @@ -2131,7 +2123,8 @@ tr_torrentSetAnnounceList( tr_torrent * tor, /* save to the .torrent file */ if( ok && !tr_bencLoadFile( &metainfo, TR_FMT_BENC, tor->info.torrent ) ) { - tr_info tmpInfo; + tr_bool hasInfo; + tr_info tmpInfo; /* remove the old fields */ tr_bencDictRemove( &metainfo, "announce" ); @@ -2160,10 +2153,8 @@ tr_torrentSetAnnounceList( tr_torrent * tor, /* try to parse it back again, to make sure it's good */ memset( &tmpInfo, 0, sizeof( tr_info ) ); - if( tr_metainfoParse( tor->session, &tmpInfo, - &tor->infoDictOffset, - &tor->infoDictLength, - &metainfo ) ) + if( tr_metainfoParse( tor->session, &metainfo, &tmpInfo, + &hasInfo, &tor->infoDictOffset, &tor->infoDictLength ) ) { /* it's good, so keep these new trackers and free the old ones */ diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index b7c101d23..e4f20e16d 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -34,8 +34,6 @@ void tr_ctorSetSave( tr_ctor * ctor, int tr_ctorGetSave( const tr_ctor * ctor ); -int tr_ctorGetMagnet( const tr_ctor * ctor, const struct tr_magnet_info ** setme ); - void tr_ctorInitTorrentPriorities( const tr_ctor * ctor, tr_torrent * tor ); void tr_ctorInitTorrentWanted( const tr_ctor * ctor, tr_torrent * tor ); diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 2ff59f31c..df747f993 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -879,8 +879,8 @@ void tr_ctorFree( tr_ctor * ctor ); /** @brief Set whether or not to delete the source .torrent file when a torrent is added. (Default: False) */ void tr_ctorSetDeleteSource( tr_ctor * ctor, tr_bool doDelete ); -/** @brief Set the link for creating a tr_torrent from a magnet link */ -int tr_ctorSetMagnet( tr_ctor * ctor, const char * magnet_link ); +/** @brief Set the constructor's metainfo from a magnet link */ +int tr_ctorSetMetainfoFromMagnetLink( tr_ctor * ctor, const char * magnet_link ); /** @brief Set the constructor's metainfo from a raw benc already in memory */ int tr_ctorSetMetainfo( tr_ctor * ctor, const uint8_t * metainfo, size_t len ); diff --git a/macosx/Torrent.m b/macosx/Torrent.m index 2e1beb3b5..fe3569d42 100644 --- a/macosx/Torrent.m +++ b/macosx/Torrent.m @@ -1563,7 +1563,7 @@ int trashDataFile(const char * filename) result = tr_ctorSetMetainfoFromFile(ctor, [path UTF8String]); if (result != TR_PARSE_OK && magnetAddress) - result = tr_ctorSetMagnet(ctor, [magnetAddress UTF8String]); + result = tr_ctorSetMetainfoFromMagnetLink(ctor, [magnetAddress UTF8String]); //backup - shouldn't be needed after upgrade to 1.70 if (result != TR_PARSE_OK && hashString) -- 2.40.0