source: trunk/libtransmission/ipc.c @ 5813

Last change on this file since 5813 was 5813, checked in by charles, 14 years ago

partial implementation of json-ipc backend: torrent start/stop/close/verify/stat/info, as are getting & setting per-torrent peer limits, upload speeds, and download speeds. this is a work in progress.

File size: 14.0 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include "transmission.h"
14#include "bencode.h"
15#include "ipc.h"
16#include "torrent.h"
17#include "utils.h"
18
19/***
20****
21***/
22
23static tr_torrent **
24getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
25{
26    tr_torrent ** torrents = NULL;
27    int torrentCount = 0;
28    tr_benc * ids;
29
30    if( tr_bencDictFindList( args, "ids", &ids ) )
31    {
32        int i;
33        const int n = tr_bencListSize( ids );
34
35        torrents = tr_new0( tr_torrent*, n );
36
37        for( i=0; i<n; ++i )
38        {
39            tr_torrent * tor = NULL;
40            tr_benc * node = tr_bencListChild( ids, i );
41            int64_t id;
42            const char * str;
43            if( tr_bencGetInt( node, &id ) )
44                tor = tr_torrentFindFromId( handle, id );
45            else if( tr_bencGetStr( node, &str ) )
46                tor = tr_torrentFindFromHashString( handle, str );
47            if( tor )
48                torrents[torrentCount++] = tor;
49        }
50    }
51    else /* all of them */
52    {
53        tr_torrent * tor = NULL;
54        const int n = tr_torrentCount( handle );
55        torrents = tr_new0( tr_torrent*, n );
56        while(( tor = tr_torrentNext( handle, tor )))
57            torrents[torrentCount++] = tor;
58    }
59
60    *setmeCount = torrentCount;
61    return torrents;
62}
63           
64static const char*
65torrentStart( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
66{
67    int i, torrentCount;
68    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
69    for( i=0; i<torrentCount; ++i )
70        tr_torrentStart( torrents[i] );
71    tr_free( torrents );
72    return NULL;
73}
74
75static const char*
76torrentStop( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
77{
78    int i, torrentCount;
79    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
80    for( i=0; i<torrentCount; ++i )
81        tr_torrentStop( torrents[i] );
82    tr_free( torrents );
83    return NULL;
84}
85
86static const char*
87torrentClose( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
88{
89    int i, torrentCount;
90    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
91    for( i=0; i<torrentCount; ++i )
92        tr_torrentClose( torrents[i] );
93    tr_free( torrents );
94    return NULL;
95}
96
97static const char*
98torrentVerify( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
99{
100    int i, torrentCount;
101    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
102    for( i=0; i<torrentCount; ++i )
103        tr_torrentVerify( torrents[i] );
104    tr_free( torrents );
105    return NULL;
106}
107
108static const char*
109torrentStatus( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
110{
111    int i, torrentCount;
112    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
113    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
114
115    for( i=0; i<torrentCount; ++i )
116    {
117        tr_torrent * tor = torrents[i];
118        const tr_stat * st = tr_torrentStat( tor );
119        tr_benc * d = tr_bencListAddDict( list, 32 );
120        tr_benc * t;
121
122        tr_bencDictAddInt( d, "id", tor->uniqueId );
123        tr_bencDictAddInt( d, "status", st->status );
124        tr_bencDictAddInt( d, "error", st->error );
125        tr_bencDictAddStr( d, "errorString", st->errorString );
126        tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
127        tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
128        tr_bencDictAddDouble( d, "percentDone", st->percentDone );
129        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
130        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
131        tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed );
132        tr_bencDictAddDouble( d, "ratio", st->ratio );
133        tr_bencDictAddInt( d, "eta", st->eta );
134        tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
135        tr_bencDictAddInt( d, "peersConnected", st->peersConnected );
136        tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
137        tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
138        tr_bencDictAddInt( d, "seeders", st->seeders );
139        tr_bencDictAddInt( d, "leechers", st->leechers );
140        tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
141        tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
142        tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
143        tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
144        tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
145        tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
146        tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
147        tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
148        tr_bencDictAddInt( d, "haveValid", st->haveValid );
149        tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
150        tr_bencDictAddInt( d, "startDate", st->startDate );
151        tr_bencDictAddInt( d, "activityDate", st->activityDate );
152        t = tr_bencDictAddDict( d, "peersFrom", 4 );
153            tr_bencDictAddInt( t, "cache",    st->peersFrom[TR_PEER_FROM_CACHE] );
154            tr_bencDictAddInt( t, "incoming", st->peersFrom[TR_PEER_FROM_INCOMING] );
155            tr_bencDictAddInt( t, "pex",      st->peersFrom[TR_PEER_FROM_PEX] );
156            tr_bencDictAddInt( t, "tracker",  st->peersFrom[TR_PEER_FROM_TRACKER] );
157        t = tr_bencDictAddDict( d, "tracker_stat", 7 );
158            tr_bencDictAddStr( t, "scrapeResponse", st->tracker_stat.scrapeResponse );
159            tr_bencDictAddStr( t, "announceResponse", st->tracker_stat.announceResponse );
160            tr_bencDictAddInt( t, "lastScrapeTime", st->tracker_stat.lastScrapeTime );
161            tr_bencDictAddInt( t, "nextScrapeTime", st->tracker_stat.nextScrapeTime );
162            tr_bencDictAddInt( t, "lastAnnounceTime", st->tracker_stat.lastAnnounceTime );
163            tr_bencDictAddInt( t, "nextAnnounceTime", st->tracker_stat.nextAnnounceTime );
164            tr_bencDictAddInt( t, "nextManualAnnounceTime", st->tracker_stat.nextManualAnnounceTime );
165    }
166
167    /* cleanup */
168    tr_free( torrents );
169    return NULL;
170}
171
172static void
173addFiles( const tr_info * info, tr_benc * files )
174{
175    unsigned int i;
176    for( i=0; i<info->fileCount; ++i )
177    {
178        const tr_file * file = &info->files[i];
179        tr_benc * d = tr_bencListAddDict( files, 4 );
180        tr_bencDictAddInt( d, "length", file->length );
181        tr_bencDictAddStr( d, "name", file->name );
182        tr_bencDictAddInt( d, "priority", file->priority );
183        tr_bencDictAddInt( d, "dnd", file->dnd );
184    }
185}
186
187static void
188addTrackers( const tr_info * info, tr_benc * trackers )
189{
190    int i;
191    for( i=0; i<info->trackerCount; ++i )
192    {
193        const tr_tracker_info * t = &info->trackers[i];
194        tr_benc * d = tr_bencListAddDict( trackers, 3 );
195        tr_bencDictAddInt( d, "tier", t->tier );
196        tr_bencDictAddStr( d, "announce", t->announce );
197        tr_bencDictAddStr( d, "scrape", t->scrape );
198    }
199}
200
201static const char*
202torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
203{
204    int i, torrentCount;
205    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
206    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
207
208    for( i=0; i<torrentCount; ++i )
209    {
210        tr_torrent * tor = torrents[i];
211        const tr_info * inf = tr_torrentInfo( tor );
212        tr_benc * d = tr_bencListAddDict( list, 13 );
213        tr_bencDictAddStr( d, "torrent", inf->torrent );
214        tr_bencDictAddStr( d, "hashString", inf->hashString );
215        tr_bencDictAddStr( d, "name", inf->name );
216        tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" );
217        tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
218        tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
219        tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
220        tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
221        tr_bencDictAddInt( d, "pieceSize", inf->pieceSize );
222        tr_bencDictAddInt( d, "pieceCount", inf->pieceCount );
223        tr_bencDictAddInt( d, "totalSize", inf->totalSize );
224        addFiles   ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
225        addTrackers( inf, tr_bencDictAddList( d, "files", inf->trackerCount ) );
226    }
227
228    /* cleanup */
229    tr_free( torrents );
230    return NULL;
231}
232
233static const char*
234torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
235{
236    int i, torrentCount;
237    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
238    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
239
240    for( i=0; i<torrentCount; ++i )
241    {
242        tr_torrent * tor = torrents[i];
243        tr_benc * d = tr_bencListAddDict( list, 3 );
244        tr_bencDictAddInt( d, "max-peers", tr_torrentGetMaxConnectedPeers( tor ) );
245        tr_bencDictAddInt( d, "speed-limit-down", tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
246        tr_bencDictAddInt( d, "speed-limit-up", tr_torrentGetSpeedLimit( tor, TR_UP ) );
247    }
248
249    tr_free( torrents );
250    return NULL;
251}
252
253static const char*
254torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
255{
256    int i, torrentCount;
257    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
258
259    for( i=0; i<torrentCount; ++i )
260    {
261        int64_t tmp;
262        tr_torrent * tor = torrents[i];
263        if( tr_bencDictFindInt( args_in, "max-peers", &tmp ) )
264            tr_torrentSetMaxConnectedPeers( tor, tmp );
265        if( tr_bencDictFindInt( args_in, "speed-limit-down", &tmp ) )
266            tr_torrentSetSpeedLimit( tor, TR_DOWN, tmp );
267        if( tr_bencDictFindInt( args_in, "speed-limit-up", &tmp ) )
268            tr_torrentSetSpeedLimit( tor, TR_UP, tmp );
269    }
270
271    tr_free( torrents );
272    return NULL;
273}
274
275static const char*
276torrentGetFile( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
277{
278    return NULL;
279}
280
281static const char*
282torrentSetFile( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
283{
284    return NULL;
285}
286
287static const char*
288sessionSet( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
289{
290    return NULL;
291}
292
293static const char*
294sessionGet( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
295{
296    return NULL;
297}
298
299static const char*
300torrentAdd( tr_handle * handle UNUSED, tr_benc * args_in UNUSED, tr_benc * args_out UNUSED )
301{
302    return NULL;
303}
304
305/***
306****
307***/
308
309static char*
310request_exec( struct tr_handle * handle,
311              tr_benc          * request,
312              int              * response_len )
313{
314    int64_t i;
315    const char * str;
316    char * out;
317    tr_benc response;
318    tr_benc * headers_in = NULL;
319    tr_benc * body_in = NULL;
320    tr_benc * args_in = NULL;
321    tr_benc * headers_out = NULL;
322    tr_benc * body_out = NULL;
323    tr_benc * args_out = NULL;
324    const char * result = NULL;
325
326    headers_in = tr_bencDictFind( request, "headers" );
327    body_in = tr_bencDictFind( request, "body" );
328    args_in = tr_bencDictFind( body_in, "args" );
329
330    /* build the response skeleton */
331    tr_bencInitDict( &response, 2 );
332    headers_out = tr_bencDictAddDict( &response, "headers", 2 );
333    tr_bencDictAddStr( headers_out, "type", "response" );
334    if( tr_bencDictFindInt( headers_in, "tag", &i ) )
335        tr_bencDictAddInt( headers_out, "tag", i );
336    body_out = tr_bencDictAddDict( &response, "body", 2 );
337    args_out = tr_bencDictAddDict( body_out, "args", 0 );
338
339    /* parse the request */
340    if( !tr_bencDictFindStr( body_in, "name", &str ) )
341        result = "no request name given";
342    else {
343             if( !strcmp( str, "torrent-start" ) )    result = torrentStart  ( handle, args_in, args_out );
344        else if( !strcmp( str, "torrent-stop" ) )     result = torrentStop   ( handle, args_in, args_out );
345        else if( !strcmp( str, "torrent-close" ) )    result = torrentClose  ( handle, args_in, args_out );
346        else if( !strcmp( str, "torrent-verify" ) )   result = torrentVerify ( handle, args_in, args_out );
347        else if( !strcmp( str, "torrent-status" ) )   result = torrentStatus ( handle, args_in, args_out );
348
349        else if( !strcmp( str, "torrent-info" ) )     result = torrentInfo ( handle, args_in, args_out );
350        else if( !strcmp( str, "torrent-add" ) )      result = torrentAdd    ( handle, args_in, args_out );
351        else if( !strcmp( str, "torrent-set" ) )      result = torrentSet    ( handle, args_in, args_out );
352        else if( !strcmp( str, "torrent-get" ) )      result = torrentGet    ( handle, args_in, args_out );
353        else if( !strcmp( str, "torrent-set-file" ) ) result = torrentSetFile( handle, args_in, args_out );
354        else if( !strcmp( str, "torrent-get-file" ) ) result = torrentGetFile( handle, args_in, args_out );
355        else if( !strcmp( str, "session-set" ) )      result = sessionSet    ( handle, args_in, args_out );
356        else if( !strcmp( str, "session-get" ) )      result = sessionGet    ( handle, args_in, args_out );
357        else                                          result = "request name not recognized";
358    }
359
360    if( !result )
361        result = "success";
362    tr_bencDictAddStr( body_out, "result", result );
363    out = tr_bencSave( &response, response_len ); /* TODO: json, not benc */
364    tr_bencFree( &response );
365    return out;
366}
367
368char*
369tr_ipc_request_exec( struct tr_handle  * handle,
370                     const void        * request_json,
371                     int                 request_len,
372                     int               * response_len )
373{
374    tr_benc top;
375    int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
376    char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
377    if( have_content )
378        tr_bencFree( &top );
379    return ret;
380}
Note: See TracBrowser for help on using the repository browser.