diff --git a/doc/ipc-json-spec.txt b/doc/ipc-json-spec.txt index c6e62d1bf..ebf096532 100644 --- a/doc/ipc-json-spec.txt +++ b/doc/ipc-json-spec.txt @@ -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 @@ -45,21 +45,17 @@ 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. @@ -118,7 +114,7 @@ } } -3.4. Torrent Status Requests +3.3. Torrent Status Requests Request name is "torrent-status". Request arguments: 3.1's optional "ids" argument. @@ -130,7 +126,7 @@ (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: @@ -146,55 +142,58 @@ 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 diff --git a/libtransmission/Makefile.am b/libtransmission/Makefile.am index c66f96284..6e9134e6f 100644 --- a/libtransmission/Makefile.am +++ b/libtransmission/Makefile.am @@ -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 index 000000000..cb2f014bd --- /dev/null +++ b/libtransmission/ipc.c @@ -0,0 +1,380 @@ +/* + * This file Copyright (C) 2008 Charles Kerr + * + * 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; iuniqueId ); + 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; ifileCount; ++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; itrackerCount; ++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; itorrent ); + 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 + * + * 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 diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index 060cccf51..21d1f5592 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -53,6 +53,30 @@ **** ***/ +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 ); diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 7c60ecdc4..c862c62aa 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -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