]> granicus.if.org Git - transmission/commitdiff
partial implementation of json-ipc backend: torrent start/stop/close/verify/stat...
authorCharles Kerr <charles@transmissionbt.com>
Mon, 12 May 2008 00:41:55 +0000 (00:41 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Mon, 12 May 2008 00:41:55 +0000 (00:41 +0000)
doc/ipc-json-spec.txt
libtransmission/Makefile.am
libtransmission/ipc.c [new file with mode: 0644]
libtransmission/ipc.h [new file with mode: 0644]
libtransmission/torrent.c
libtransmission/torrent.h

index c6e62d1bff5d347a3606fbff8a4ce152b2c5e0d5..ebf09653267118280198c1f9133810272e251008 100644 (file)
@@ -12,7 +12,7 @@
 
 2.  Message Format
 
-   The entire protocol is formatted in a subset of JSON that understands
+   Messages are formatted in a subset of JSON that understands
    arrays, maps, strings, and whole numbers with no exponentials --
    in short, the subset of JSON easily represented in benc.
    floating-point numbers are represented as strings.
@@ -20,7 +20,7 @@
 
    There are only two message types: request and response.  Both
    are JSON objects with two members:  "headers" (described in 2.1)
-   and "body" (described in 2.2-2.3).
+   and "body" (described in 2.2 - 2.3).
 
 2.1.  Headers
 
 
 3.  Torrent Requests
 
-3.1.  Common Arguments
-
-   Most torrent requests support an "ids" argument, which is a list
-   containing unique torrent ids, or torrent sha1 hash strings, or both.
-   These are the torrents that the request will be applied to.
-   If "ids" is omitted, the request is applied to all torrents.
-
-3.2.  Torrent Action Requests
+3.1.  Torrent Action Requests
 
    Request names: "torrent-start", "torrent-stop",
                   "torrent-remove", "torrent-verify"
-   Request arguments: 3.1's optional "ids" argument.
+   Request arguments: "ids", a list of unique torrent ids, sha1 hash strings,
+                      or both.  These are the torrents that the request will
+                      be applied to.  If "ids" is ommitted, the request is
+                      applied to all torrents.
    Response arguments: none.
 
-3.3.  Torrent Info Requests
+3.2.  Torrent Info Requests
 
    Request name: "torrent-info".
    Request arguments: 3.1's optional "ids" argument.
          }
       }
 
-3.4.  Torrent Status Requests
+3.3.  Torrent Status Requests
 
    Request name is "torrent-status".
    Request arguments: 3.1's optional "ids" argument.
    (2) a new string, "announce-url", is added
    (3) a new string, "scrape-url", is added
 
-3.5.  Adding a Torrent
+3.4.  Adding a Torrent
 
    Request name: "torrent-add"
    Request arguments:
 
    The "filename" argument is required; all others are optional.
 
-   Response arguments: 3.1's "error" if the request failed.
+   Response arguments: none.
 
-3.6.  Other torrent settings
+3.5.  Other torrent settings
 
    Common arguments:
 
    string             | value type & description
    -------------------+-------------------------------------------------
-   "id"               | int or string  torrent id or hash string
    "max-peers"        | int            maximum number of peers
    "speed-limit-down" | int            maximum download speed (in KiB/s)
    "speed-limit-up"   | int            maximum upload speed (in KiB/s)
 
-3.6.1.  Mutators
+3.5.1.  Mutators
 
    Request name: "torrent-set"
-   Request arguments: "id" from 3.6, plus one or more of 3.6's other arguments
+   Request arguments: 3.1's "ids", plus one or more of 3.5's arguments
    Response arguments: none
 
-3.6.2.  Accessors
+3.5.2.  Accessors
 
    Request name: "torrent-get"
    Request arguments: none
-   Response arguments: all of 3.6's arguments
+   Response arguments: "torrents", a list of torrent objects containing
+                       all of 3.5's arguments plus the id passed in
+                       by "torrent-set".
+                      
 
-3.7  File Priorities
+3.6  File Priorities
 
    Common arguments:
 
    string             | value type & description
    -------------------+-------------------------------------------------
-   "id"               | int or string  torrent id or hash string
    "priority-high"    | array          indices of one or more high-priority files
    "priority-low"     | array          indices of one or more low-priority files
    "priority-normal"  | array          indices of one or more normal-priority files
    "download"         | array          indices of one or more file to download
    "no-download"      | array          indices of one or more file to not download
 
-3.7.1.  Mutators
+3.6.1.  Mutators
 
     Request name: "torrent-set-file"
-    Request arguments: "id" from 3.7, plus one or more of 3.7's other arguments
+    Request arguments: 3.1's "ids", plus one or more of 3.6's arguments
     Response arguments: none
 
-3.7.2.  Accessors
+3.6.2.  Accessors
 
     Request name: "torrent-get-file"
     Request arguments: none
-    Response arguments: all of 3.7's arguments
+   Response arguments: list of objects, one per torrent, containing
+                       all of 3.6's arguments plus the id passed in
+                       by "torrent-set".
    
 4.   Session Status Requests
 
index c66f962846b8c2cf3233af09964784844d6c51c3..6e9134e6f3d310d0a1bdb2515059ca21b6edfaa8 100644 (file)
@@ -16,6 +16,7 @@ libtransmission_a_SOURCES = \
     ggets.c \
     handshake.c \
     inout.c \
+    ipc.c \
     ipcparse.c \
     json.c \
     list.c \
@@ -56,6 +57,7 @@ noinst_HEADERS = \
     ggets.h \
     handshake.h \
     inout.h \
+    ipc.h \
     ipcparse.h \
     list.h \
     makemeta.h \
diff --git a/libtransmission/ipc.c b/libtransmission/ipc.c
new file mode 100644 (file)
index 0000000..cb2f014
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
+ *
+ * This file is licensed by the GPL version 2.  Works owned by the
+ * Transmission project are granted a special exemption to clause 2(b)
+ * so that the bulk of its code can remain under the MIT license. 
+ * This exemption does not extend to derived works not owned by
+ * the Transmission project.
+ *
+ * $Id:$
+ */
+
+#include "transmission.h"
+#include "bencode.h"
+#include "ipc.h"
+#include "torrent.h"
+#include "utils.h"
+
+/***
+****
+***/
+
+static tr_torrent **
+getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
+{
+    tr_torrent ** torrents = NULL;
+    int torrentCount = 0;
+    tr_benc * ids;
+
+    if( tr_bencDictFindList( args, "ids", &ids ) )
+    {
+        int i;
+        const int n = tr_bencListSize( ids );
+
+        torrents = tr_new0( tr_torrent*, n );
+
+        for( i=0; i<n; ++i )
+        {
+            tr_torrent * tor = NULL;
+            tr_benc * node = tr_bencListChild( ids, i );
+            int64_t id;
+            const char * str;
+            if( tr_bencGetInt( node, &id ) )
+                tor = tr_torrentFindFromId( handle, id );
+            else if( tr_bencGetStr( node, &str ) )
+                tor = tr_torrentFindFromHashString( handle, str );
+            if( tor )
+                torrents[torrentCount++] = tor;
+        }
+    }
+    else /* all of them */
+    {
+        tr_torrent * tor = NULL;
+        const int n = tr_torrentCount( handle );
+        torrents = tr_new0( tr_torrent*, n );
+        while(( tor = tr_torrentNext( handle, tor )))
+            torrents[torrentCount++] = tor;
+    }
+
+    *setmeCount = torrentCount;
+    return torrents;
+}
+            
+static const char*
+torrentStart( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    for( i=0; i<torrentCount; ++i )
+        tr_torrentStart( torrents[i] );
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentStop( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    for( i=0; i<torrentCount; ++i )
+        tr_torrentStop( torrents[i] );
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentClose( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    for( i=0; i<torrentCount; ++i )
+        tr_torrentClose( torrents[i] );
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentVerify( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    for( i=0; i<torrentCount; ++i )
+        tr_torrentVerify( torrents[i] );
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentStatus( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
+
+    for( i=0; i<torrentCount; ++i )
+    {
+        tr_torrent * tor = torrents[i];
+        const tr_stat * st = tr_torrentStat( tor );
+        tr_benc * d = tr_bencListAddDict( list, 32 );
+        tr_benc * t;
+
+        tr_bencDictAddInt( d, "id", tor->uniqueId );
+        tr_bencDictAddInt( d, "status", st->status );
+        tr_bencDictAddInt( d, "error", st->error );
+        tr_bencDictAddStr( d, "errorString", st->errorString );
+        tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
+        tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
+        tr_bencDictAddDouble( d, "percentDone", st->percentDone );
+        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
+        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
+        tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed );
+        tr_bencDictAddDouble( d, "ratio", st->ratio );
+        tr_bencDictAddInt( d, "eta", st->eta );
+        tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
+        tr_bencDictAddInt( d, "peersConnected", st->peersConnected );
+        tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
+        tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
+        tr_bencDictAddInt( d, "seeders", st->seeders );
+        tr_bencDictAddInt( d, "leechers", st->leechers );
+        tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
+        tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
+        tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
+        tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
+        tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
+        tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
+        tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
+        tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
+        tr_bencDictAddInt( d, "haveValid", st->haveValid );
+        tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
+        tr_bencDictAddInt( d, "startDate", st->startDate );
+        tr_bencDictAddInt( d, "activityDate", st->activityDate );
+        t = tr_bencDictAddDict( d, "peersFrom", 4 );
+            tr_bencDictAddInt( t, "cache",    st->peersFrom[TR_PEER_FROM_CACHE] );
+            tr_bencDictAddInt( t, "incoming", st->peersFrom[TR_PEER_FROM_INCOMING] );
+            tr_bencDictAddInt( t, "pex",      st->peersFrom[TR_PEER_FROM_PEX] );
+            tr_bencDictAddInt( t, "tracker",  st->peersFrom[TR_PEER_FROM_TRACKER] );
+        t = tr_bencDictAddDict( d, "tracker_stat", 7 );
+            tr_bencDictAddStr( t, "scrapeResponse", st->tracker_stat.scrapeResponse );
+            tr_bencDictAddStr( t, "announceResponse", st->tracker_stat.announceResponse );
+            tr_bencDictAddInt( t, "lastScrapeTime", st->tracker_stat.lastScrapeTime );
+            tr_bencDictAddInt( t, "nextScrapeTime", st->tracker_stat.nextScrapeTime );
+            tr_bencDictAddInt( t, "lastAnnounceTime", st->tracker_stat.lastAnnounceTime );
+            tr_bencDictAddInt( t, "nextAnnounceTime", st->tracker_stat.nextAnnounceTime );
+            tr_bencDictAddInt( t, "nextManualAnnounceTime", st->tracker_stat.nextManualAnnounceTime );
+    }
+
+    /* cleanup */
+    tr_free( torrents );
+    return NULL;
+}
+
+static void
+addFiles( const tr_info * info, tr_benc * files )
+{
+    unsigned int i;
+    for( i=0; i<info->fileCount; ++i )
+    {
+        const tr_file * file = &info->files[i];
+        tr_benc * d = tr_bencListAddDict( files, 4 );
+        tr_bencDictAddInt( d, "length", file->length );
+        tr_bencDictAddStr( d, "name", file->name );
+        tr_bencDictAddInt( d, "priority", file->priority );
+        tr_bencDictAddInt( d, "dnd", file->dnd );
+    }
+}
+
+static void
+addTrackers( const tr_info * info, tr_benc * trackers )
+{
+    int i;
+    for( i=0; i<info->trackerCount; ++i )
+    {
+        const tr_tracker_info * t = &info->trackers[i];
+        tr_benc * d = tr_bencListAddDict( trackers, 3 );
+        tr_bencDictAddInt( d, "tier", t->tier );
+        tr_bencDictAddStr( d, "announce", t->announce );
+        tr_bencDictAddStr( d, "scrape", t->scrape );
+    }
+}
+
+static const char*
+torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
+
+    for( i=0; i<torrentCount; ++i )
+    {
+        tr_torrent * tor = torrents[i];
+        const tr_info * inf = tr_torrentInfo( tor );
+        tr_benc * d = tr_bencListAddDict( list, 13 );
+        tr_bencDictAddStr( d, "torrent", inf->torrent );
+        tr_bencDictAddStr( d, "hashString", inf->hashString );
+        tr_bencDictAddStr( d, "name", inf->name );
+        tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" );
+        tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
+        tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
+        tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
+        tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
+        tr_bencDictAddInt( d, "pieceSize", inf->pieceSize );
+        tr_bencDictAddInt( d, "pieceCount", inf->pieceCount );
+        tr_bencDictAddInt( d, "totalSize", inf->totalSize );
+        addFiles   ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
+        addTrackers( inf, tr_bencDictAddList( d, "files", inf->trackerCount ) );
+    }
+
+    /* cleanup */
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
+
+    for( i=0; i<torrentCount; ++i )
+    {
+        tr_torrent * tor = torrents[i];
+        tr_benc * d = tr_bencListAddDict( list, 3 );
+        tr_bencDictAddInt( d, "max-peers", tr_torrentGetMaxConnectedPeers( tor ) );
+        tr_bencDictAddInt( d, "speed-limit-down", tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
+        tr_bencDictAddInt( d, "speed-limit-up", tr_torrentGetSpeedLimit( tor, TR_UP ) );
+    }
+
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
+{
+    int i, torrentCount;
+    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
+
+    for( i=0; i<torrentCount; ++i )
+    {
+        int64_t tmp;
+        tr_torrent * tor = torrents[i];
+        if( tr_bencDictFindInt( args_in, "max-peers", &tmp ) )
+            tr_torrentSetMaxConnectedPeers( tor, tmp );
+        if( tr_bencDictFindInt( args_in, "speed-limit-down", &tmp ) )
+            tr_torrentSetSpeedLimit( tor, TR_DOWN, tmp );
+        if( tr_bencDictFindInt( args_in, "speed-limit-up", &tmp ) )
+            tr_torrentSetSpeedLimit( tor, TR_UP, tmp );
+    }
+
+    tr_free( torrents );
+    return NULL;
+}
+
+static const char*
+torrentGetFile( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
+{
+    return NULL;
+}
+
+static const char*
+torrentSetFile( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
+{
+    return NULL;
+}
+
+static const char*
+sessionSet( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
+{
+    return NULL;
+}
+
+static const char*
+sessionGet( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
+{
+    return NULL;
+}
+
+static const char*
+torrentAdd( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
+{
+    return NULL;
+}
+
+/***
+****
+***/
+
+static char*
+request_exec( struct tr_handle * handle,
+              tr_benc          * request,
+              int              * response_len )
+{
+    int64_t i;
+    const char * str;
+    char * out;
+    tr_benc response;
+    tr_benc * headers_in = NULL;
+    tr_benc * body_in = NULL;
+    tr_benc * args_in = NULL;
+    tr_benc * headers_out = NULL;
+    tr_benc * body_out = NULL;
+    tr_benc * args_out = NULL;
+    const char * result = NULL;
+
+    headers_in = tr_bencDictFind( request, "headers" );
+    body_in = tr_bencDictFind( request, "body" );
+    args_in = tr_bencDictFind( body_in, "args" );
+
+    /* build the response skeleton */
+    tr_bencInitDict( &response, 2 );
+    headers_out = tr_bencDictAddDict( &response, "headers", 2 );
+    tr_bencDictAddStr( headers_out, "type", "response" );
+    if( tr_bencDictFindInt( headers_in, "tag", &i ) )
+        tr_bencDictAddInt( headers_out, "tag", i );
+    body_out = tr_bencDictAddDict( &response, "body", 2 );
+    args_out = tr_bencDictAddDict( body_out, "args", 0 );
+
+    /* parse the request */
+    if( !tr_bencDictFindStr( body_in, "name", &str ) )
+        result = "no request name given";
+    else {
+             if( !strcmp( str, "torrent-start" ) )    result = torrentStart  ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-stop" ) )     result = torrentStop   ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-close" ) )    result = torrentClose  ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-verify" ) )   result = torrentVerify ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-status" ) )   result = torrentStatus ( handle, args_in, args_out );
+
+        else if( !strcmp( str, "torrent-info" ) )     result = torrentInfo ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-add" ) )      result = torrentAdd    ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-set" ) )      result = torrentSet    ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-get" ) )      result = torrentGet    ( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-set-file" ) ) result = torrentSetFile( handle, args_in, args_out );
+        else if( !strcmp( str, "torrent-get-file" ) ) result = torrentGetFile( handle, args_in, args_out );
+        else if( !strcmp( str, "session-set" ) )      result = sessionSet    ( handle, args_in, args_out );
+        else if( !strcmp( str, "session-get" ) )      result = sessionGet    ( handle, args_in, args_out );
+        else                                          result = "request name not recognized";
+    }
+
+    if( !result )
+        result = "success";
+    tr_bencDictAddStr( body_out, "result", result );
+    out = tr_bencSave( &response, response_len ); /* TODO: json, not benc */
+    tr_bencFree( &response );
+    return out;
+}
+
+char*
+tr_ipc_request_exec( struct tr_handle  * handle,
+                     const void        * request_json,
+                     int                 request_len,
+                     int               * response_len )
+{
+    tr_benc top;
+    int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
+    char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
+    if( have_content )
+        tr_bencFree( &top );
+    return ret;
+}
diff --git a/libtransmission/ipc.h b/libtransmission/ipc.h
new file mode 100644 (file)
index 0000000..0d3e39d
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
+ *
+ * This file is licensed by the GPL version 2.  Works owned by the
+ * Transmission project are granted a special exemption to clause 2(b)
+ * so that the bulk of its code can remain under the MIT license. 
+ * This exemption does not extend to derived works not owned by
+ * the Transmission project.
+ *
+ * $Id:$
+ */
+
+#ifndef TR_IPC_H
+#define TR_IPC_H
+
+struct tr_handle;
+
+char*
+tr_ipc_request_exec( struct tr_handle  * handle,
+                     const void        * request_json,
+                     int                 request_len,
+                     int               * response_len );
+
+#endif
index 060cccf51b252a416bbee517c1f0e571a23a950a..21d1f559293f141e0217ee198df6f4223b8e717b 100644 (file)
 ****
 ***/
 
+tr_torrent*
+tr_torrentFindFromId( tr_handle * handle, int id )
+{
+    tr_torrent * tor = NULL;
+
+    while(( tor = tr_torrentNext( handle, tor )))
+        if( tor->uniqueId == id )
+            return tor;
+
+    return NULL;
+}
+
+tr_torrent*
+tr_torrentFindFromHashString( tr_handle * handle, const char * str )
+{
+    tr_torrent * tor = NULL;
+
+    while(( tor = tr_torrentNext( handle, tor )))
+        if( !strcmp( str, tor->info.hashString ) )
+            return tor;
+
+    return NULL;
+}
+
 int
 tr_torrentExists( const tr_handle * handle,
                   const uint8_t   * torrentHash )
@@ -368,10 +392,12 @@ torrentRealInit( tr_handle     * h,
     uint64_t loaded;
     uint64_t t;
     tr_info * info = &tor->info;
+    static int nextUniqueId = 1;
    
     tr_globalLock( h );
 
     tor->handle   = h;
+    tor->uniqueId = nextUniqueId++;
 
     randomizeTiers( info );
 
index 7c60ecdc4c2937d0146528de0973ff90f962248c..c862c62aa6b57253aaa6c91b8f072b963d59f881 100644 (file)
@@ -49,7 +49,9 @@ int  tr_torrentIsSeed  ( const tr_torrent * );
 void tr_torrentChangeMyPort  ( tr_torrent * );
 
 int tr_torrentExists( const tr_handle *, const uint8_t * );
+tr_torrent* tr_torrentFindFromId( tr_handle *, int id );
 tr_torrent* tr_torrentFindFromHash( tr_handle *, const uint8_t * );
+tr_torrent* tr_torrentFindFromHashString( tr_handle *, const char * );
 tr_torrent* tr_torrentFindFromObfuscatedHash( tr_handle *, const uint8_t* );
 
 void tr_torrentGetRates( const tr_torrent *, float * toClient, float * toPeer );
@@ -178,6 +180,8 @@ struct tr_torrent
     tr_stat                    stats;
 
     tr_torrent               * next;
+
+    int                        uniqueId;
 };
 
 #endif