Changeset 9550


Ignore:
Timestamp:
Nov 24, 2009, 2:16:31 AM (13 years ago)
Author:
charles
Message:

(trunk) #2096: Magnet, BEP #9 support

Location:
trunk
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/add-dialog.c

    r9547 r9550  
    493493            else
    494494            {
    495                 GtkWidget * w = gtk_message_dialog_new( GTK_WINDOW( dialog ),
    496                                                         GTK_DIALOG_MODAL,
     495                GtkWidget * w = gtk_message_dialog_new( GTK_WINDOW( dialog ), 0,
    497496                                                        GTK_MESSAGE_ERROR,
    498497                                                        GTK_BUTTONS_CLOSE,
     
    500499                gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
    501500                    _( "Transmission doesn't know how to use \"%s\"" ), url );
    502                 gtk_dialog_run( GTK_DIALOG( w ) );
    503                 gtk_widget_destroy( w );
     501                g_signal_connect_swapped( w, "response",
     502                                          G_CALLBACK( gtk_widget_destroy ), w );
     503                gtk_widget_show( w );
    504504                destroy = FALSE;
    505505            }
  • trunk/gtk/icons.c

    r9194 r9550  
    231231    const char * stock_name;
    232232
    233     if( !strcmp( mime_type, DIRECTORY_MIME_TYPE ) )
     233    if( !strcmp( mime_type, UNKNOWN_MIME_TYPE ) )
     234        stock_name = GTK_STOCK_MISSING_IMAGE;
     235    else if( !strcmp( mime_type, DIRECTORY_MIME_TYPE ) )
    234236        stock_name = GTK_STOCK_DIRECTORY;
    235237    else
  • trunk/gtk/icons.h

    r7999 r9550  
    88
    99#define DIRECTORY_MIME_TYPE "folder"
     10#define UNKNOWN_MIME_TYPE "unknown"
    1011
    1112const char * get_mime_type_from_filename( const char *file );
  • trunk/gtk/torrent-cell-renderer.c

    r9172 r9550  
    307307    const tr_info * info = tr_torrentInfo( tor );
    308308
    309     if( info->fileCount > 1 )
     309    if( info->fileCount == 0  )
     310        mime_type = UNKNOWN_MIME_TYPE;
     311    else if( info->fileCount > 1 )
    310312        mime_type = DIRECTORY_MIME_TYPE;
    311313    else
  • trunk/gtk/tr-core.c

    r9547 r9550  
    10241024tr_core_add_from_url( TrCore * core, const char * url )
    10251025{
     1026    tr_session * session = tr_core_session( core );
     1027
    10261028    if( gtr_is_magnet_link( url ) )
    10271029    {
    1028         g_message( "FIXME: magnet link \"%s\" not handled", url );
     1030        tr_ctor * ctor = tr_ctorNew( session );
     1031        int err = tr_ctorSetMagnet( ctor, url );
     1032        if( !err )
     1033        {
     1034            tr_session * session = tr_core_session( core );
     1035            TrTorrent * gtor = tr_torrent_new_ctor( session, ctor, &err );
     1036            if( !err )
     1037                tr_core_add_torrent( core, gtor, FALSE );
     1038            else
     1039                g_message( "tr_torrent_new_ctor err %d", err );
     1040        }
     1041        else
     1042        {
     1043            GtkWidget * w = gtk_message_dialog_new( NULL, 0,
     1044                                                    GTK_MESSAGE_ERROR,
     1045                                                    GTK_BUTTONS_CLOSE,
     1046                                                    "%s", _( "Unrecognized URL" ) );
     1047            gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
     1048                _( "Transmission doesn't know how to use \"%s\"" ), url );
     1049            g_signal_connect_swapped( w, "response",
     1050                                      G_CALLBACK( gtk_widget_destroy ), w );
     1051            gtk_widget_show( w );
     1052            tr_ctorFree( ctor );
     1053        }
    10291054    }
    10301055    else
     
    10321057        struct url_dialog_data * data = g_new( struct url_dialog_data, 1 );
    10331058        data->core = core;
    1034         tr_webRun( tr_core_session( core ), url, NULL, onURLDone, data );
     1059        tr_webRun( session, url, NULL, onURLDone, data );
    10351060    }
    10361061}
     
    10521077        return;
    10531078
     1079g_message( "filename [%s]", filename );
    10541080    if( gtr_is_supported_url( filename ) || gtr_is_magnet_link( filename ) )
    10551081    {
  • trunk/gtk/util.c

    r9547 r9550  
    347347    for( i=0; i<argc; ++i )
    348348    {
    349         if( gtr_is_supported_url( argv[i] ) )
     349        if( gtr_is_supported_url( argv[i] ) || gtr_is_magnet_link( argv[i] ) )
    350350        {
    351351            ret = g_slist_prepend( ret, g_strdup( argv[i] ) );
  • trunk/libtransmission/Makefile.am

    r9531 r9550  
    4848    torrent.c \
    4949    torrent-ctor.c \
     50    torrent-magnet.c \
    5051    tr-dht.c \
    5152    tr-getopt.c \
     
    9596    stats.h \
    9697    torrent.h \
     98    torrent-magnet.h \
    9799    tr-getopt.h \
    98100    transmission.h \
  • trunk/libtransmission/completion.c

    r8212 r9550  
    1717#include "completion.h"
    1818#include "torrent.h"
     19#include "torrent-magnet.h"
    1920#include "utils.h"
    2021
     
    241242tr_cpGetStatus( const tr_completion * cp )
    242243{
     244    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
    243245    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
    244246    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
     
    255257    const uint64_t            lastPieceSize  = tor->lastPieceSize;
    256258    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
     259
     260    if( !tr_torrentHasMetadata( tor ) )
     261        return 0;
    257262
    258263    for( i=0; i!=lastPiece; ++i )
  • trunk/libtransmission/metainfo.c

    r9170 r9550  
    3838#include "bencode.h"
    3939#include "crypto.h" /* tr_sha1 */
     40#include "magnet.h"
    4041#include "metainfo.h"
    4142#include "platform.h"
     
    228229
    229230static char *
    230 announceToScrape( const char * announce )
     231tr_convertAnnounceToScrape( const char * announce )
    231232{
    232233    char *       scrape = NULL;
     
    295296                        t->tier = validTiers;
    296297                        t->announce = tr_strdup( url );
    297                         t->scrape = announceToScrape( url );
     298                        t->scrape = tr_convertAnnounceToScrape( url );
    298299
    299300                        anyAdded = TRUE;
     
    325326            trackers[trackerCount].tier = 0;
    326327            trackers[trackerCount].announce = tr_strdup( url );
    327             trackers[trackerCount++].scrape = announceToScrape( url );
     328            trackers[trackerCount++].scrape = tr_convertAnnounceToScrape( url );
    328329            /*fprintf( stderr, "single announce: [%s]\n", url );*/
    329330        }
     
    382383static const char*
    383384tr_metainfoParseImpl( const tr_session * session,
    384                       tr_info *         inf,
    385                       const tr_benc *   meta_in )
     385                      tr_info          * inf,
     386                      int              * infoDictOffset,
     387                      int              * infoDictLength,
     388                      const tr_benc    * meta_in )
    386389{
    387390    int64_t         i;
     
    405408        tr_sha1_to_hex( inf->hashString, inf->hash );
    406409        escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH );
     410
     411        if( infoDictLength != NULL )
     412            *infoDictLength = len;
     413
     414        if( infoDictOffset != NULL )
     415        {
     416            int mlen = 0;
     417            char * mstr = tr_bencToStr( meta_in, TR_FMT_BENC, &mlen );
     418            const char * offset = tr_memmem( mstr, mlen, bstr, len );
     419            if( offset != NULL )
     420                *infoDictOffset = offset - mstr;
     421            tr_free( mstr );
     422            if( offset == NULL )
     423                return "info";
     424        }
     425
    407426        tr_free( bstr );
    408427    }
     
    484503tr_metainfoParse( const tr_session * session,
    485504                  tr_info          * inf,
     505                  int              * infoDictOffset,
     506                  int              * infoDictLength,
    486507                  const tr_benc    * meta_in )
    487508{
    488     const char * badTag = tr_metainfoParseImpl( session, inf, meta_in );
     509    const char * badTag = tr_metainfoParseImpl( session,
     510                                                inf,
     511                                                infoDictOffset,
     512                                                infoDictLength,
     513                                                meta_in );
    489514    const tr_bool success = badTag == NULL;
    490515
     
    501526tr_metainfoFree( tr_info * inf )
    502527{
     528    int i;
    503529    tr_file_index_t ff;
    504     int             i;
    505530
    506531    for( i = 0; i < inf->webseedCount; ++i )
     
    543568}
    544569
     570/***
     571****
     572***/
     573
     574void
     575tr_metainfoSetFromMagnet( tr_info * inf, const tr_magnet_info * m )
     576{
     577    /* hash */
     578    memcpy( inf->hash, m->hash, 20 );
     579    tr_sha1_to_hex( inf->hashString, inf->hash );
     580    escape( inf->hashEscaped, inf->hash, SHA_DIGEST_LENGTH );
     581
     582    /* name */
     583    if( *m->displayName )
     584        inf->name = tr_strdup( m->displayName );
     585    else
     586        inf->name = tr_strdup( inf->hashString );
     587
     588    /* trackers */
     589    if( m->announceCount > 0 )
     590    {
     591        int i;
     592        const int n = m->announceCount;
     593
     594        inf->trackerCount = n;
     595        inf->trackers = tr_new0( tr_tracker_info, n );
     596        for( i=0; i<n; ++i ) {
     597            const char * url = m->announceURLs[i];
     598            inf->trackers[i].tier = i;
     599            inf->trackers[i].announce = tr_strdup( url );
     600            inf->trackers[i].scrape = tr_convertAnnounceToScrape( url );
     601        }
     602    }
     603}
  • trunk/libtransmission/metainfo.h

    r8871 r9550  
    2424
    2525#ifndef __TRANSMISSION__
    26 #error only libtransmission should #include this header.
     26 #error only libtransmission should #include this header.
    2727#endif
    2828
     
    3333
    3434struct tr_benc;
     35struct tr_magnet_info;
    3536
    3637tr_bool  tr_metainfoParse( const tr_session     * session,
    37                            tr_info              * info,
     38                           tr_info              * setmeInfo,
     39                           int                  * setmeInfoDictLength,
     40                           int                  * setmeInfoDictOffset,
    3841                           const struct tr_benc * benc );
    3942
     
    4447                         tr_info    * inf );
    4548
     49void tr_metainfoSetFromMagnet( tr_info * inf, const struct tr_magnet_info * m );
     50
     51
    4652#endif
  • trunk/libtransmission/peer-mgr.c

    r9548 r9550  
    344344{
    345345    tr_peer * peer = tr_new0( tr_peer, 1 );
     346    tr_bitsetConstructor( &peer->have, 0 );
    346347    peer->atom = atom;
    347348    return peer;
     
    384385    tr_peerIoUnref( peer->io ); /* balanced by the ref in handshakeDoneCB() */
    385386
    386     tr_bitfieldFree( peer->have );
     387    tr_bitsetDestructor( &peer->have );
    387388    tr_bitfieldFree( peer->blame );
    388389    tr_free( peer->client );
     
    907908    Torrent * t;
    908909    struct weighted_piece * pieces;
    909     const tr_bitfield * have = peer->have;
     910    const tr_bitset * have = &peer->have;
    910911    const time_t now = time( NULL );
    911912
     
    929930
    930931        /* if the peer has this piece that we want... */
    931         if( tr_bitfieldHasFast( have, p->index ) )
     932        if( tr_bitsetHasFast( have, p->index ) )
    932933        {
    933934            tr_block_index_t b = tr_torPieceFirstBlock( tor, p->index );
     
    19421943            int j;
    19431944            for( j = 0; j < peerCount; ++j )
    1944                 if( tr_bitfieldHas( peers[j]->have, i ) )
     1945                if( tr_bitsetHas( &peers[j]->have, i ) )
    19451946                    ++tab[i];
    19461947        }
     
    19651966    peers = (const tr_peer**) tr_ptrArrayBase( &t->peers );
    19661967    for( i=0; i<peerCount; ++i )
    1967         tr_bitfieldOr( pieces, peers[i]->have );
     1968        tr_bitsetOr( pieces, &peers[i]->have );
    19681969
    19691970    managerUnlock( t->manager );
     
    23522353        else {
    23532354            tr_bitfield * tmp = tr_bitfieldDup( tr_cpPieceBitfield( &tor->completion ) );
    2354             tr_bitfieldDifference( tmp, peer->have );
     2355            tr_bitsetDifference( tmp, &peer->have );
    23552356            peerHasEverything = tr_bitfieldCountTrueBits( tmp ) == 0;
    23562357            tr_bitfieldFree( tmp );
  • trunk/libtransmission/peer-mgr.h

    r9532 r9550  
    2525
    2626#include "bitfield.h"
     27#include "bitset.h"
    2728#include "net.h"
    2829#include "peer-common.h" /* struct peer_request */
     
    9495
    9596    struct tr_bitfield     * blame;
    96     struct tr_bitfield     * have;
     97    struct tr_bitset        have;
    9798
    9899    /** how complete the peer's copy of the torrent is. [0.0...1.0] */
  • trunk/libtransmission/peer-msgs.c

    r9549 r9550  
    3636#include "stats.h"
    3737#include "torrent.h"
     38#include "torrent-magnet.h"
    3839#include "tr-dht.h"
    3940#include "utils.h"
     
    6768    LTEP_HANDSHAKE          = 0,
    6869
    69     TR_LTEP_PEX             = 1,
     70    UT_PEX_ID               = 1,
     71    UT_METADATA_ID          = 3,
    7072
    7173    MAX_PEX_PEER_COUNT      = 50,
    7274
    73     MIN_CHOKE_PERIOD_SEC    = ( 10 ),
     75    MIN_CHOKE_PERIOD_SEC    = 10,
    7476
    7577    /* idle seconds before we send a keepalive */
     
    7981
    8082    REQQ                    = 512,
     83
     84    METADATA_REQQ           = 64,
    8185
    8286    MAX_BLOCK_SIZE          = ( 1024 * 16 ),
     
    9296
    9397    /* number of pieces we'll allow in our fast set */
    94     MAX_FAST_SET_SIZE = 3
     98    MAX_FAST_SET_SIZE = 3,
     99
     100    /* defined in BEP #9 */
     101    METADATA_MSG_TYPE_REQUEST = 0,
     102    METADATA_MSG_TYPE_DATA = 1,
     103    METADATA_MSG_TYPE_REJECT = 2
    95104};
    96105
     
    166175{
    167176    tr_bool         peerSupportsPex;
     177    tr_bool         peerSupportsMetadataXfer;
    168178    tr_bool         clientSentLtepHandshake;
    169179    tr_bool         peerSentLtepHandshake;
     180    tr_bool         requestingMetadataFromPeer;
     181
    170182    /*tr_bool         haveFastSet;*/
    171183
     
    182194    uint8_t         state;
    183195    uint8_t         ut_pex_id;
     196    uint8_t         ut_metadata_id;
    184197    uint16_t        pexCount;
    185198    uint16_t        pexCount6;
     
    200213    struct peer_request    peerAskedFor[REQQ];
    201214    int                    peerAskedForCount;
    202  
     215
     216    int                    peerAskedForMetadata[METADATA_REQQ];
     217    int                    peerAskedForMetadataCount;
     218
    203219    tr_pex               * pex;
    204220    tr_pex               * pex6;
     
    219235    struct event          pexTimer;
    220236};
     237
     238/**
     239***
     240**/
     241
     242#if 0
     243static tr_bitfield*
     244getHave( const struct tr_peermsgs * msgs )
     245{
     246    if( msgs->peer->have == NULL )
     247        msgs->peer->have = tr_bitfieldNew( msgs->torrent->info.pieceCount );
     248    return msgs->peer->have;
     249}
     250#endif
    221251
    222252static TR_INLINE tr_session*
     
    655685    const tr_torrent * torrent = msgs->torrent;
    656686
    657     return ( !torrent->info.pieces[piece].dnd )                 /* we want it */
     687    return ( !torrent->info.pieces[piece].dnd )                  /* we want it */
    658688          && ( !tr_cpPieceIsComplete( &torrent->completion, piece ) ) /* !have */
    659           && ( tr_bitfieldHas( msgs->peer->have, piece ) );    /* peer has it */
     689          && ( tr_bitsetHas( &msgs->peer->have, piece ) );      /* peer has it */
    660690}
    661691
     
    678708    bitfield = tr_cpPieceBitfield( &torrent->completion );
    679709
    680     if( !msgs->peer->have )
    681         return TRUE;
    682 
    683     assert( bitfield->byteCount == msgs->peer->have->byteCount );
    684 
    685710    for( i = 0; i < torrent->info.pieceCount; ++i )
    686711        if( isPieceInteresting( msgs, i ) )
     
    715740    if( i != msgs->peer->clientIsInterested )
    716741        sendInterest( msgs, i );
     742}
     743
     744static tr_bool
     745popNextMetadataRequest( tr_peermsgs * msgs, int * piece )
     746{
     747    if( msgs->peerAskedForMetadataCount == 0 )
     748        return FALSE;
     749
     750    *piece = msgs->peerAskedForMetadata[0];
     751
     752    memmove( msgs->peerAskedForMetadata,
     753             msgs->peerAskedForMetadata + 1,
     754             sizeof( int ) * --msgs->peerAskedForMetadataCount );
     755
     756    return TRUE;
    717757}
    718758
     
    820860    char * buf;
    821861    int len;
    822     int pex;
     862    tr_bool allow_pex;
     863    tr_bool allow_metadata_xfer;
    823864    struct evbuffer * out = msgs->outMessages;
    824865    const unsigned char * ipv6 = tr_globalIPv6();
     
    830871    msgs->clientSentLtepHandshake = 1;
    831872
     873    /* decide if we want to advertise metadata xfer support (BEP 9) */
     874    if( tr_torrentIsPrivate( msgs->torrent ) )
     875        allow_metadata_xfer = 0;
     876    else
     877        allow_metadata_xfer = 1;
     878
    832879    /* decide if we want to advertise pex support */
    833880    if( !tr_torrentAllowsPex( msgs->torrent ) )
    834         pex = 0;
     881        allow_pex = 0;
    835882    else if( msgs->peerSentLtepHandshake )
    836         pex = msgs->peerSupportsPex ? 1 : 0;
     883        allow_pex = msgs->peerSupportsPex ? 1 : 0;
    837884    else
    838         pex = 1;
    839 
    840     tr_bencInitDict( &val, 7 );
     885        allow_pex = 1;
     886
     887    tr_bencInitDict( &val, 8 );
    841888    tr_bencDictAddInt( &val, "e", getSession(msgs)->encryptionMode != TR_CLEAR_PREFERRED );
    842     if( ipv6 )
     889    if( ipv6 != NULL )
    843890        tr_bencDictAddRaw( &val, "ipv6", ipv6, 16 );
     891    if( allow_metadata_xfer && tr_torrentHasMetadata( msgs->torrent )
     892                            && ( msgs->torrent->infoDictLength > 0 ) )
     893        tr_bencDictAddInt( &val, "metadata_size", msgs->torrent->infoDictLength );
    844894    tr_bencDictAddInt( &val, "p", tr_sessionGetPeerPort( getSession(msgs) ) );
    845895    tr_bencDictAddInt( &val, "reqq", REQQ );
    846896    tr_bencDictAddInt( &val, "upload_only", tr_torrentIsSeed( msgs->torrent ) );
    847897    tr_bencDictAddStr( &val, "v", TR_NAME " " USERAGENT_PREFIX );
    848     m  = tr_bencDictAddDict( &val, "m", 1 );
    849     if( pex )
    850         tr_bencDictAddInt( m, "ut_pex", TR_LTEP_PEX );
     898    m  = tr_bencDictAddDict( &val, "m", 2 );
     899    if( allow_metadata_xfer )
     900        tr_bencDictAddInt( m, "ut_metadata", UT_METADATA_ID );
     901    if( allow_pex )
     902        tr_bencDictAddInt( m, "ut_pex", UT_PEX_ID );
     903
    851904    buf = tr_bencToStr( &val, TR_FMT_BENC, &len );
    852905
     
    899952    /* check supported messages for utorrent pex */
    900953    msgs->peerSupportsPex = 0;
     954    msgs->peerSupportsMetadataXfer = 0;
     955
    901956    if( tr_bencDictFindDict( &val, "m", &sub ) ) {
    902957        if( tr_bencDictFindInt( sub, "ut_pex", &i ) ) {
     958            msgs->peerSupportsPex = i != 0;
    903959            msgs->ut_pex_id = (uint8_t) i;
    904             msgs->peerSupportsPex = msgs->ut_pex_id == 0 ? 0 : 1;
    905960            dbgmsg( msgs, "msgs->ut_pex is %d", (int)msgs->ut_pex_id );
    906961        }
    907     }
     962        if( tr_bencDictFindInt( sub, "ut_metadata", &i ) ) {
     963            msgs->peerSupportsMetadataXfer = i != 0;
     964            msgs->ut_metadata_id = (uint8_t) i;
     965            dbgmsg( msgs, "msgs->ut_metadata_id is %d", (int)msgs->ut_metadata_id );
     966        }
     967    }
     968
     969    /* look for metainfo size (BEP 9) */
     970    if( tr_bencDictFindInt( &val, "metadata_size", &i ) )
     971        tr_torrentSetMetadataSizeHint( msgs->torrent, i );
    908972
    909973    /* look for upload_only (BEP 21) */
     
    926990        tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_ALT, &pex );
    927991    }
    928  
     992
    929993    if( tr_bencDictFindRaw( &val, "ipv6", &addr, &addr_len) && addr_len == 16 ) {
    930994        pex.addr.type = TR_AF_INET6;
     
    9381002
    9391003    tr_bencFree( &val );
     1004    tr_free( tmp );
     1005}
     1006
     1007static void
     1008parseUtMetadata( tr_peermsgs * msgs, int msglen, struct evbuffer * inbuf )
     1009{
     1010    tr_benc dict;
     1011    char * msg_end;
     1012    char * benc_end;
     1013    int64_t msg_type = -1;
     1014    int64_t piece = -1;
     1015    int64_t total_size = 0;
     1016    uint8_t * tmp = tr_new( uint8_t, msglen );
     1017
     1018    tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, msglen );
     1019    msg_end = (char*)tmp + msglen;
     1020
     1021    if( !tr_bencLoad( tmp, msglen, &dict, &benc_end ) )
     1022    {
     1023        tr_bencDictFindInt( &dict, "msg_type", &msg_type );
     1024        tr_bencDictFindInt( &dict, "piece", &piece );
     1025        tr_bencDictFindInt( &dict, "total_size", &total_size );
     1026        tr_bencFree( &dict );
     1027    }
     1028
     1029    dbgmsg( msgs, "got ut_metadata msg: type %d, piece %d, total_size %d",
     1030            (int)msg_type, (int)piece, (int)total_size );
     1031
     1032    if( msg_type == METADATA_MSG_TYPE_REJECT )
     1033    {
     1034        /* NOOP */
     1035    }
     1036
     1037    if( ( msg_type == METADATA_MSG_TYPE_DATA )
     1038        && ( !tr_torrentHasMetadata( msgs->torrent ) )
     1039        && ( msg_end - benc_end <= METADATA_PIECE_SIZE )
     1040        && ( piece * METADATA_PIECE_SIZE + (msg_end - benc_end) <= total_size ) )
     1041    {
     1042        const int pieceLen = msg_end - benc_end;
     1043dbgmsg( msgs, "got a metadata piece... calling tr_torrentSetMetadataPiece" );
     1044        msgs->requestingMetadataFromPeer = FALSE;
     1045        tr_torrentSetMetadataPiece( msgs->torrent, piece, benc_end, pieceLen );
     1046    }
     1047
     1048    if( msg_type == METADATA_MSG_TYPE_REQUEST )
     1049    {
     1050        if( ( piece >= 0 )
     1051            && tr_torrentHasMetadata( msgs->torrent )
     1052            && !tr_torrentIsPrivate( msgs->torrent )
     1053            && ( msgs->peerAskedForMetadataCount < METADATA_REQQ ) )
     1054        {
     1055            msgs->peerAskedForMetadata[msgs->peerAskedForMetadataCount++] = piece;
     1056        }
     1057        else
     1058        {
     1059            tr_benc tmp;
     1060            int payloadLen;
     1061            char * payload;
     1062            tr_peerIo  * io  = msgs->peer->io;
     1063            struct evbuffer * out = msgs->outMessages;
     1064
     1065            /* build the rejection message */
     1066            tr_bencInitDict( &tmp, 2 );
     1067            tr_bencDictAddInt( &tmp, "msg_type", METADATA_MSG_TYPE_REJECT );
     1068            tr_bencDictAddInt( &tmp, "piece", piece );
     1069            payload = tr_bencToStr( &tmp, TR_FMT_BENC, &payloadLen );
     1070            tr_bencFree( &tmp );
     1071
     1072            /* write it out as a LTEP message to our outMessages buffer */
     1073            tr_peerIoWriteUint32( io, out, 2 * sizeof( uint8_t ) + payloadLen );
     1074            tr_peerIoWriteUint8 ( io, out, BT_LTEP );
     1075            tr_peerIoWriteUint8 ( io, out, msgs->ut_metadata_id );
     1076            tr_peerIoWriteBytes ( io, out, payload, payloadLen );
     1077            pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
     1078            dbgOutMessageLen( msgs );
     1079
     1080            tr_free( payload );
     1081        }
     1082    }
     1083
    9401084    tr_free( tmp );
    9411085}
     
    10181162        }
    10191163    }
    1020     else if( ltep_msgid == TR_LTEP_PEX )
     1164    else if( ltep_msgid == UT_PEX_ID )
    10211165    {
    10221166        dbgmsg( msgs, "got ut pex" );
    10231167        msgs->peerSupportsPex = 1;
    10241168        parseUtPex( msgs, msglen, inbuf );
     1169    }
     1170    else if( ltep_msgid == UT_METADATA_ID )
     1171    {
     1172        dbgmsg( msgs, "got ut metadata" );
     1173        msgs->peerSupportsMetadataXfer = 1;
     1174        parseUtMetadata( msgs, msglen, inbuf );
    10251175    }
    10261176    else
     
    10881238updatePeerProgress( tr_peermsgs * msgs )
    10891239{
    1090     msgs->peer->progress = tr_bitfieldCountTrueBits( msgs->peer->have ) / (float)msgs->torrent->info.pieceCount;
     1240    msgs->peer->progress = tr_bitsetPercent( &msgs->peer->have );
    10911241    dbgmsg( msgs, "peer progress is %f", msgs->peer->progress );
    10921242    updateFastSet( msgs );
     
    12871437            tr_peerIoReadUint32( msgs->peer->io, inbuf, &ui32 );
    12881438            dbgmsg( msgs, "got Have: %u", ui32 );
    1289             if( tr_bitfieldAdd( msgs->peer->have, ui32 ) ) {
     1439            if( tr_bitsetAdd( &msgs->peer->have, ui32 ) ) {
    12901440                fireError( msgs, ERANGE );
    12911441                return READ_ERR;
     
    12961446        case BT_BITFIELD:
    12971447            dbgmsg( msgs, "got a bitfield" );
    1298             tr_peerIoReadBytes( msgs->peer->io, inbuf, msgs->peer->have->bits, msglen );
     1448            tr_bitsetReserve( &msgs->peer->have, msglen*8 );
     1449            tr_peerIoReadBytes( msgs->peer->io, inbuf, msgs->peer->have.bitfield.bits, msglen );
    12991450            updatePeerProgress( msgs );
    13001451            break;
     
    13191470            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.length );
    13201471            dbgmsg( msgs, "got a Cancel %u:%u->%u", r.index, r.offset, r.length );
     1472
    13211473            for( i=0; i<msgs->peerAskedForCount; ++i ) {
    13221474                const struct peer_request * req = msgs->peerAskedFor + i;
     
    13241476                    break;
    13251477            }
     1478
    13261479            if( i < msgs->peerAskedForCount )
    1327                 memmove( msgs->peerAskedFor+i, msgs->peerAskedFor+i+1, --msgs->peerAskedForCount-i );
     1480                memmove( msgs->peerAskedFor+i,
     1481                         msgs->peerAskedFor+i+1,
     1482                         sizeof(struct peer_request) *( --msgs->peerAskedForCount-i) );
    13281483            break;
    13291484        }
     
    13671522            dbgmsg( msgs, "Got a BT_FEXT_HAVE_ALL" );
    13681523            if( fext ) {
    1369                 tr_bitfieldAddRange( msgs->peer->have, 0, msgs->torrent->info.pieceCount );
     1524                tr_bitsetSetHaveAll( &msgs->peer->have );
    13701525                updatePeerProgress( msgs );
    13711526            } else {
     
    13781533            dbgmsg( msgs, "Got a BT_FEXT_HAVE_NONE" );
    13791534            if( fext ) {
    1380                 tr_bitfieldClear( msgs->peer->have );
     1535                tr_bitsetSetHaveNone( &msgs->peer->have );
    13811536                updatePeerProgress( msgs );
    13821537            } else {
     
    15871742
    15881743static void
    1589 updateRequests( tr_peermsgs * msgs )
     1744updateMetadataRequests( tr_peermsgs * msgs, time_t now )
     1745{
     1746    int piece;
     1747
     1748    if( msgs->peerSupportsMetadataXfer
     1749        && !msgs->requestingMetadataFromPeer
     1750        && tr_torrentGetNextMetadataRequest( msgs->torrent, now, &piece ) )
     1751    {
     1752        tr_benc tmp;
     1753        int payloadLen;
     1754        char * payload;
     1755        tr_peerIo  * io  = msgs->peer->io;
     1756        struct evbuffer * out = msgs->outMessages;
     1757
     1758        /* build the data message */
     1759        tr_bencInitDict( &tmp, 3 );
     1760        tr_bencDictAddInt( &tmp, "msg_type", METADATA_MSG_TYPE_REQUEST );
     1761        tr_bencDictAddInt( &tmp, "piece", piece );
     1762        payload = tr_bencToStr( &tmp, TR_FMT_BENC, &payloadLen );
     1763        tr_bencFree( &tmp );
     1764
     1765        dbgmsg( msgs, "requesting metadata piece #%d", piece );
     1766
     1767        /* write it out as a LTEP message to our outMessages buffer */
     1768        tr_peerIoWriteUint32( io, out, 2 * sizeof( uint8_t ) + payloadLen );
     1769        tr_peerIoWriteUint8 ( io, out, BT_LTEP );
     1770        tr_peerIoWriteUint8 ( io, out, msgs->ut_metadata_id );
     1771        tr_peerIoWriteBytes ( io, out, payload, payloadLen );
     1772        pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
     1773        dbgOutMessageLen( msgs );
     1774
     1775        msgs->requestingMetadataFromPeer = TRUE;
     1776
     1777        tr_free( payload );
     1778    }
     1779}
     1780
     1781static void
     1782updateBlockRequests( tr_peermsgs * msgs )
    15901783{
    15911784    const int MIN_BATCH_SIZE = 4;
     
    16421835fillOutputBuffer( tr_peermsgs * msgs, time_t now )
    16431836{
     1837    int piece;
    16441838    size_t bytesWritten = 0;
    16451839    struct peer_request req;
     
    16691863
    16701864    /**
    1671     ***  Blocks
     1865    ***  Metadata Pieces
     1866    **/
     1867
     1868    if( ( tr_peerIoGetWriteBufferSpace( msgs->peer->io, now ) >= METADATA_PIECE_SIZE )
     1869        && popNextMetadataRequest( msgs, &piece ) )
     1870    {
     1871        char * data;
     1872        int dataLen;
     1873        tr_bool ok = FALSE;
     1874
     1875        data = tr_torrentGetMetadataPiece( msgs->torrent, piece, &dataLen );
     1876        if( ( dataLen > 0 ) && ( data != NULL ) )
     1877        {
     1878            tr_benc tmp;
     1879            int payloadLen;
     1880            char * payload;
     1881            tr_peerIo  * io  = msgs->peer->io;
     1882            struct evbuffer * out = msgs->outMessages;
     1883
     1884            /* build the data message */
     1885            tr_bencInitDict( &tmp, 3 );
     1886            tr_bencDictAddInt( &tmp, "msg_type", METADATA_MSG_TYPE_DATA );
     1887            tr_bencDictAddInt( &tmp, "piece", piece );
     1888            tr_bencDictAddInt( &tmp, "total_size", dataLen );
     1889            payload = tr_bencToStr( &tmp, TR_FMT_BENC, &payloadLen );
     1890            tr_bencFree( &tmp );
     1891
     1892            /* write it out as a LTEP message to our outMessages buffer */
     1893            tr_peerIoWriteUint32( io, out, 2 * sizeof( uint8_t ) + payloadLen + dataLen );
     1894            tr_peerIoWriteUint8 ( io, out, BT_LTEP );
     1895            tr_peerIoWriteUint8 ( io, out, msgs->ut_metadata_id );
     1896            tr_peerIoWriteBytes ( io, out, payload, payloadLen );
     1897            tr_peerIoWriteBytes ( io, out, data, dataLen );
     1898            pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
     1899            dbgOutMessageLen( msgs );
     1900
     1901            tr_free( payload );
     1902            tr_free( data );
     1903
     1904            ok = TRUE;
     1905        }
     1906
     1907        if( !ok ) /* send a rejection message */
     1908        {
     1909            tr_benc tmp;
     1910            int payloadLen;
     1911            char * payload;
     1912            tr_peerIo  * io  = msgs->peer->io;
     1913            struct evbuffer * out = msgs->outMessages;
     1914
     1915            /* build the rejection message */
     1916            tr_bencInitDict( &tmp, 2 );
     1917            tr_bencDictAddInt( &tmp, "msg_type", METADATA_MSG_TYPE_REJECT );
     1918            tr_bencDictAddInt( &tmp, "piece", piece );
     1919            payload = tr_bencToStr( &tmp, TR_FMT_BENC, &payloadLen );
     1920            tr_bencFree( &tmp );
     1921
     1922            /* write it out as a LTEP message to our outMessages buffer */
     1923            tr_peerIoWriteUint32( io, out, 2 * sizeof( uint8_t ) + payloadLen );
     1924            tr_peerIoWriteUint8 ( io, out, BT_LTEP );
     1925            tr_peerIoWriteUint8 ( io, out, msgs->ut_metadata_id );
     1926            tr_peerIoWriteBytes ( io, out, payload, payloadLen );
     1927            pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
     1928            dbgOutMessageLen( msgs );
     1929
     1930            tr_free( payload );
     1931        }
     1932    }
     1933
     1934    /**
     1935    ***  Data Blocks
    16721936    **/
    16731937
     
    17502014    if ( tr_isPeerIo( msgs->peer->io ) ) {
    17512015        updateDesiredRequestCount( msgs, now );
    1752         updateRequests( msgs );
     2016        updateBlockRequests( msgs );
     2017        updateMetadataRequests( msgs, now );
    17532018    }
    17542019
     
    21122377    m->peer->clientIsInterested = 0;
    21132378    m->peer->peerIsInterested = 0;
    2114     m->peer->have = tr_bitfieldNew( torrent->info.pieceCount );
    21152379    m->state = AWAITING_BT_LENGTH;
    21162380    m->outMessages = evbuffer_new( );
     
    21682432    tr_publisherUnsubscribe( &peer->publisher, tag );
    21692433}
    2170 
  • trunk/libtransmission/rpcimpl.c

    r9538 r9550  
    10941094        else
    10951095        {
    1096             if( filename != NULL )
    1097                 tr_ctorSetMetainfoFromFile( ctor, filename );
    1098             else {
     1096            if( filename == NULL )
     1097            {
    10991098                int len;
    1100                 char * metainfo = tr_base64_decode( metainfo_base64, -1,  &len );
     1099                char * metainfo = tr_base64_decode( metainfo_base64, -1, &len );
    11011100                tr_ctorSetMetainfo( ctor, (uint8_t*)metainfo, len );
    11021101                tr_free( metainfo );
    11031102            }
     1103            else if( !strncmp( filename, "magnet:?", 8 ) )
     1104            {
     1105                tr_ctorSetMagnet( ctor, filename );
     1106            }
     1107            else
     1108            {
     1109                tr_ctorSetMetainfoFromFile( ctor, filename );
     1110            }
     1111
    11041112            addTorrentImpl( idle_data, ctor );
    11051113        }
  • trunk/libtransmission/torrent-ctor.c

    r9341 r9550  
    1414#include "transmission.h"
    1515#include "bencode.h"
     16#include "magnet.h"
    1617#include "platform.h"
    1718#include "session.h" /* tr_sessionFindTorrentFile() */
     
    4243    tr_benc                 metainfo;
    4344    char *                  sourceFile;
     45
     46    tr_magnet_info        * magnetInfo;
    4447
    4548    struct optional_args    optionalArgs[2];
     
    100103{
    101104    return ctor->sourceFile;
     105}
     106
     107int
     108tr_ctorSetMagnet( tr_ctor * ctor, const char * uri )
     109{
     110    int err;
     111
     112    if( ctor->magnetInfo != NULL )
     113        tr_magnetFree( ctor->magnetInfo );
     114
     115    ctor->magnetInfo = tr_magnetParse( uri );
     116
     117    err = ctor->magnetInfo == NULL;
     118    return err;
    102119}
    103120
     
    373390
    374391int
     392tr_ctorGetMagnet( const tr_ctor * ctor, const tr_magnet_info ** setme )
     393{
     394    int err = 0;
     395
     396    if( ctor->magnetInfo == NULL )
     397        err = 1;
     398    else
     399        *setme = ctor->magnetInfo;
     400
     401    return err;
     402}
     403
     404int
    375405tr_ctorGetMetainfo( const tr_ctor *  ctor,
    376406                    const tr_benc ** setme )
  • trunk/libtransmission/torrent.c

    r9549 r9550  
    3333#include "resume.h"
    3434#include "fdlimit.h" /* tr_fdTorrentClose */
     35#include "magnet.h"
    3536#include "metainfo.h"
    3637#include "peer-mgr.h"
     
    4445#include "verify.h"
    4546
    46 #define MAX_BLOCK_SIZE ( 1024 * 16 )
     47enum
     48{
     49    MAX_BLOCK_SIZE = 1024 * 16
     50};
    4751
    4852/***
     
    551555}
    552556
    553 static void refreshCurrentDir( tr_torrent * tor );;
     557static void refreshCurrentDir( tr_torrent * tor );
    554558
    555559static void
    556 torrentRealInit( tr_torrent * tor, const tr_ctor * ctor )
    557 {
    558     int          doStart;
    559     uint64_t     loaded;
    560     uint64_t     t;
    561     const char * dir;
    562     static int   nextUniqueId = 1;
    563     tr_info    * info = &tor->info;
    564     tr_session * session = tr_ctorGetSession( ctor );
    565 
    566     assert( session != NULL );
    567 
    568     tr_globalLock( session );
    569 
    570     tor->session   = session;
    571     tor->uniqueId = nextUniqueId++;
    572     tor->magicNumber = TORRENT_MAGIC_NUMBER;
    573 
    574     randomizeTiers( info );
    575 
    576     tor->bandwidth = tr_bandwidthNew( session, session->bandwidth );
     560torrentInitFromInfo( tr_torrent * tor )
     561{
     562    uint64_t t;
     563    tr_info * info = &tor->info;
    577564
    578565    tor->blockSize = getBlockSize( info->pieceSize );
    579566
    580     if( !tr_ctorGetDownloadDir( ctor, TR_FORCE, &dir ) ||
    581         !tr_ctorGetDownloadDir( ctor, TR_FALLBACK, &dir ) )
    582             tor->downloadDir = tr_strdup( dir );
    583 
    584     if( tr_ctorGetIncompleteDir( ctor, &dir ) )
    585         dir = tr_sessionGetIncompleteDir( session );
    586     if( tr_sessionIsIncompleteDirEnabled( session ) )
    587         tor->incompleteDir = tr_strdup( dir );
    588 
    589     tor->lastPieceSize = info->totalSize % info->pieceSize;
     567    if( info->pieceSize )
     568        tor->lastPieceSize = info->totalSize % info->pieceSize;
    590569
    591570    if( !tor->lastPieceSize )
    592571        tor->lastPieceSize = info->pieceSize;
    593572
    594     tor->lastBlockSize = info->totalSize % tor->blockSize;
     573    if( tor->blockSize )
     574        tor->lastBlockSize = info->totalSize % tor->blockSize;
    595575
    596576    if( !tor->lastBlockSize )
    597577        tor->lastBlockSize = tor->blockSize;
    598578
    599     tor->blockCount =
    600         ( info->totalSize + tor->blockSize - 1 ) / tor->blockSize;
    601 
    602     tor->blockCountInPiece =
    603         info->pieceSize / tor->blockSize;
    604 
    605     tor->blockCountInLastPiece =
    606         ( tor->lastPieceSize + tor->blockSize - 1 ) / tor->blockSize;
     579    tor->blockCount = tor->blockSize
     580        ? ( info->totalSize + tor->blockSize - 1 ) / tor->blockSize
     581        : 0;
     582
     583    tor->blockCountInPiece = tor->blockSize
     584        ? info->pieceSize / tor->blockSize
     585        : 0;
     586
     587    tor->blockCountInLastPiece = tor->blockSize
     588        ? ( tor->lastPieceSize + tor->blockSize - 1 ) / tor->blockSize
     589        : 0;
    607590
    608591    /* check our work */
    609     assert( ( info->pieceSize % tor->blockSize ) == 0 );
     592    if( tor->blockSize != 0 )
     593        assert( ( info->pieceSize % tor->blockSize ) == 0 );
    610594    t = info->pieceCount - 1;
    611595    t *= info->pieceSize;
     
    625609    tr_torrentInitFilePieces( tor );
    626610
     611    tr_bitfieldConstruct( &tor->checkedPieces, tor->info.pieceCount );
     612
     613    tor->completeness = tr_cpGetStatus( &tor->completion );
     614}
     615
     616void
     617tr_torrentGotNewInfoDict( tr_torrent * tor )
     618{
     619    torrentInitFromInfo( tor );
     620}
     621
     622static void
     623torrentInit( tr_torrent * tor, const tr_ctor * ctor )
     624{
     625    int doStart;
     626    uint64_t loaded;
     627    const char * dir;
     628    static int nextUniqueId = 1;
     629    tr_session * session = tr_ctorGetSession( ctor );
     630
     631    assert( session != NULL );
     632
     633    tr_globalLock( session );
     634
     635    tor->session   = session;
     636    tor->uniqueId = nextUniqueId++;
     637    tor->magicNumber = TORRENT_MAGIC_NUMBER;
     638
     639    randomizeTiers( &tor->info );
     640
    627641    tr_sha1( tor->obfuscatedHash, "req2", 4,
    628              info->hash, SHA_DIGEST_LENGTH,
     642             tor->info.hash, SHA_DIGEST_LENGTH,
    629643             NULL );
     644
     645    if( !tr_ctorGetDownloadDir( ctor, TR_FORCE, &dir ) ||
     646        !tr_ctorGetDownloadDir( ctor, TR_FALLBACK, &dir ) )
     647            tor->downloadDir = tr_strdup( dir );
     648
     649    if( tr_ctorGetIncompleteDir( ctor, &dir ) )
     650        dir = tr_sessionGetIncompleteDir( session );
     651    if( tr_sessionIsIncompleteDirEnabled( session ) )
     652        tor->incompleteDir = tr_strdup( dir );
     653
     654    tor->bandwidth = tr_bandwidthNew( session, session->bandwidth );
     655
     656    tor->error = TR_STAT_OK;
    630657
    631658    tr_peerMgrAddTorrent( session->peerMgr, tor );
     
    638665    tr_ctorInitTorrentWanted( ctor, tor );
    639666
    640     tor->error = TR_STAT_OK;
    641 
    642     tr_bitfieldConstruct( &tor->checkedPieces, tor->info.pieceCount );
    643667    tr_torrentUncheck( tor );
    644668
     
    668692    }
    669693
    670     tor->completeness = tr_cpGetStatus( &tor->completion );
    671 
    672694    {
    673695        tr_torrent * it = NULL;
     
    683705    }
    684706
    685     tr_globalUnlock( session );
     707    torrentInitFromInfo( tor );
    686708
    687709    /* maybe save our own copy of the metainfo */
     
    691713        if( !tr_ctorGetMetainfo( ctor, &val ) )
    692714        {
    693             const char * filename = tor->info.torrent;
    694             tr_bencToFile( val, TR_FMT_BENC, filename );
    695             tr_sessionSetTorrentFile( tor->session, tor->info.hashString, filename );
     715            const char * path = tor->info.torrent;
     716            tr_bencToFile( val, TR_FMT_BENC, path );
     717            tr_sessionSetTorrentFile( tor->session, tor->info.hashString, path );
    696718        }
    697719    }
    698720
    699     tor->tiers = tr_announcerAddTorrent( session->announcer, tor );
     721    tor->tiers = tr_announcerAddTorrent( tor->session->announcer, tor );
    700722    tor->tiersSubscription = tr_announcerSubscribe( tor->tiers, onTrackerResponse, tor );
    701 
    702     tr_metainfoMigrate( session, &tor->info );
    703723
    704724    if( doStart )
    705725        torrentStart( tor );
     726
     727    tr_globalUnlock( session );
    706728}
    707729
     
    723745        return TR_PARSE_ERR;
    724746
    725     didParse = tr_metainfoParse( session, setmeInfo, metainfo );
     747    didParse = tr_metainfoParse( session, setmeInfo, NULL, NULL, metainfo );
    726748    doFree = didParse && ( setmeInfo == &tmp );
    727749
     
    745767               int            * setmeError )
    746768{
    747     int          err;
    748     tr_info      tmpInfo;
     769    int err;
     770    tr_info tmpInfo;
    749771    tr_torrent * tor = NULL;
     772    const tr_magnet_info * magnetInfo;
    750773
    751774    assert( ctor != NULL );
    752775    assert( tr_isSession( tr_ctorGetSession( ctor ) ) );
    753776
    754     err = tr_torrentParse( ctor, &tmpInfo );
    755     if( !err )
     777    if( !tr_ctorGetMagnet( ctor, &magnetInfo ) )
    756778    {
    757779        tor = tr_new0( tr_torrent, 1 );
    758         tor->info = tmpInfo;
    759         torrentRealInit( tor, ctor );
    760     }
    761     else if( setmeError )
    762     {
    763         *setmeError = err;
     780        tr_metainfoSetFromMagnet( &tor->info, magnetInfo );
     781        torrentInit( tor, ctor );
     782    }
     783    else
     784    {
     785        err = tr_torrentParse( ctor, &tmpInfo );
     786        if( !err )
     787        {
     788            tor = tr_new0( tr_torrent, 1 );
     789            tor->info = tmpInfo;
     790            torrentInit( tor, ctor );
     791        }
     792        else if( setmeError )
     793        {
     794            *setmeError = err;
     795        }
    764796    }
    765797
     
    9891021                tor->etaDLSpeedCalculatedAt = now;
    9901022            }
    991            
     1023
    9921024            if( s->leftUntilDone > s->desiredAvailable )
    9931025                s->eta = TR_ETA_NOT_AVAIL;
     
    10071039                    tor->etaULSpeedCalculatedAt = now;
    10081040                }
    1009                
     1041
    10101042                if( s->pieceUploadSpeed < 0.1 )
    10111043                    s->eta = TR_ETA_UNKNOWN;
     
    10211053            break;
    10221054    }
    1023    
    1024     if( !checkSeedRatio || s->ratio >= seedRatio || s->ratio == TR_RATIO_INF ) 
    1025         s->percentRatio = 1.0; 
    1026     else if( s->ratio == TR_RATIO_NA ) 
    1027         s->percentRatio = 0.0; 
    1028     else 
    1029         s->percentRatio = s->ratio / seedRatio; 
     1055
     1056    if( !checkSeedRatio || s->ratio >= seedRatio || s->ratio == TR_RATIO_INF )
     1057        s->percentRatio = 1.0;
     1058    else if( s->ratio == TR_RATIO_NA )
     1059        s->percentRatio = 0.0;
     1060    else
     1061        s->percentRatio = s->ratio / seedRatio;
    10301062
    10311063    tr_torrentUnlock( tor );
     
    20972129        /* try to parse it back again, to make sure it's good */
    20982130        memset( &tmpInfo, 0, sizeof( tr_info ) );
    2099         if( tr_metainfoParse( tor->session, &tmpInfo, &metainfo ) )
     2131        if( tr_metainfoParse( tor->session, &tmpInfo,
     2132                              &tor->infoDictOffset,
     2133                              &tor->infoDictLength,
     2134                              &metainfo ) )
    21002135        {
    21012136            /* it's good, so keep these new trackers and free the old ones */
     
    23682403        tr_free( path );
    23692404
    2370        
    23712405        tmp = tr_torrentBuildPartial( tor, 0 );
    23722406        path = tr_buildPath( tor->currentDir, tmp, NULL );
     
    26572691}
    26582692
    2659 
    26602693char*
    26612694tr_torrentFindFile( const tr_torrent * tor, tr_file_index_t fileNum )
  • trunk/libtransmission/torrent.h

    r9549 r9550  
    2626struct tr_ratecontrol;
    2727struct tr_torrent_tiers;
     28struct tr_magnet_info;
    2829
    2930/**
     
    3536
    3637int         tr_ctorGetSave( const tr_ctor * ctor );
     38
     39int         tr_ctorGetMagnet( const tr_ctor * ctor, const struct tr_magnet_info ** setme );
    3740
    3841void        tr_ctorInitTorrentPriorities( const tr_ctor * ctor, tr_torrent * tor );
     
    132135                                           tr_verify_state   state );
    133136
     137struct tr_incomplete_metadata;
     138
    134139struct tr_torrent
    135140{
     
    143148
    144149    uint8_t                  obfuscatedHash[SHA_DIGEST_LENGTH];
     150
     151    /* Used when the torrent has been created with a magnet link
     152     * and we're in the process of downloading the metainfo from
     153     * other peers */
     154    struct tr_incomplete_metadata  * incompleteMetadata;
    145155
    146156    /* If the initiator of the connection receives a handshake in which the
     
    159169    char * incompleteDir;
    160170
     171    /* Length, in bytes, of the "info" dict in the .torrent file */
     172    int infoDictLength;
     173
     174    /* Offset, in bytes, of the beginning of the "info" dict in the .torrent file */
     175    int infoDictOffset;
     176
    161177    /* Where the files are now.
    162178     * This pointer will be equal to downloadDir or incompleteDir */
     
    340356/* set a flag indicating that the torrent's .resume file
    341357 * needs to be saved when the torrent is closed */
    342 static TR_INLINE void tr_torrentSetDirty( tr_torrent * tor )
     358static TR_INLINE
     359void tr_torrentSetDirty( tr_torrent * tor )
    343360{
    344361    assert( tr_isTorrent( tor ) );
     
    347364}
    348365
    349 static TR_INLINE const char * tr_torrentName( const tr_torrent * tor )
     366static TR_INLINE
     367const char * tr_torrentName( const tr_torrent * tor )
    350368{
    351369    assert( tr_isTorrent( tor ) );
     
    383401char* tr_torrentBuildPartial( const tr_torrent *, tr_file_index_t fileNo );
    384402
     403/* for when the info dict has been fundamentally changed wrt files,
     404 * piece size, etc. such as in BEP 9 where peers exchange metadata */
     405void tr_torrentGotNewInfoDict( tr_torrent * tor );
    385406
    386407#endif
  • trunk/libtransmission/transmission.h

    r9538 r9550  
    859859                                    tr_bool   doDelete );
    860860
     861int         tr_ctorSetMagnet( tr_ctor * ctor,
     862                              const char * url );
     863
    861864int         tr_ctorSetMetainfo( tr_ctor *       ctor,
    862865                                const uint8_t * metainfo,
  • trunk/libtransmission/utils-test.c

    r9544 r9550  
    298298}
    299299
     300static int
     301test_array( void )
     302{
     303    int i;
     304    int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     305    int n = sizeof( array ) / sizeof( array[0] );
     306
     307    tr_removeElementFromArray( array, 5, sizeof( int ), n-- );
     308    for( i=0; i<n; ++i )
     309        check( array[i] == ( i<5 ? i : i+1 ) );
     310
     311    tr_removeElementFromArray( array, 0, sizeof( int ), n-- );
     312    for( i=0; i<n; ++i )
     313        check( array[i] == ( i<4 ? i+1 : i+2 ) );
     314
     315    tr_removeElementFromArray( array, n-1, sizeof( int ), n ); n--;
     316    for( i=0; i<n; ++i )
     317        check( array[i] == ( i<4 ? i+1 : i+2 ) );
     318
     319    return 0;
     320}
     321
    300322int
    301323main( void )
     
    339361    if( ( i = test_memmem( ) ) )
    340362        return i;
     363    if( ( i = test_array( ) ) )
     364        return i;
    341365
    342366    /* test that tr_cryptoRandInt() stays in-bounds */
  • trunk/libtransmission/utils.c

    r9531 r9550  
    14161416    return 0;
    14171417}
     1418
     1419/***
     1420****
     1421***/
     1422
     1423void
     1424tr_removeElementFromArray( void * array, int index_to_remove,
     1425                           size_t sizeof_element, size_t nmemb )
     1426{
     1427    char * a = array;
     1428
     1429    memmove( a + sizeof_element * index_to_remove,
     1430             a + sizeof_element * ( index_to_remove  + 1 ),
     1431             sizeof_element * ( --nmemb - index_to_remove ) );
     1432}
  • trunk/libtransmission/utils.h

    r9531 r9550  
    425425
    426426/** on success, return 0.  on failure, return -1 and set errno */
    427 int tr_moveFile( const char * oldpath, const char * newpath, tr_bool * renamed ) TR_GNUC_NONNULL(1,2);
    428 
     427int tr_moveFile( const char * oldpath, const char * newpath,
     428                 tr_bool * renamed ) TR_GNUC_NONNULL(1,2);
     429
     430void tr_removeElementFromArray( void * array, int index_to_remove,
     431                                size_t sizeof_element, size_t nmemb );
    429432
    430433#ifdef __cplusplus
Note: See TracChangeset for help on using the changeset viewer.