source: trunk/libtransmission/ipc.c @ 5819

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

ipc: add session accessor/mutators.
transmission.h: make the session API more consistent.

File size: 20.5 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 <assert.h>
14#include <string.h> /* strcmp */
15
16#include "transmission.h"
17#include "bencode.h"
18#include "ipc.h"
19#include "torrent.h"
20#include "utils.h"
21
22#define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( (ary)[0] ) )
23
24/***
25****
26***/
27
28static tr_torrent **
29getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
30{
31    tr_torrent ** torrents = NULL;
32    int torrentCount = 0;
33    tr_benc * ids;
34
35    if( tr_bencDictFindList( args, "ids", &ids ) )
36    {
37        int i;
38        const int n = tr_bencListSize( ids );
39
40        torrents = tr_new0( tr_torrent*, n );
41
42        for( i=0; i<n; ++i )
43        {
44            tr_torrent * tor = NULL;
45            tr_benc * node = tr_bencListChild( ids, i );
46            int64_t id;
47            const char * str;
48            if( tr_bencGetInt( node, &id ) )
49                tor = tr_torrentFindFromId( handle, id );
50            else if( tr_bencGetStr( node, &str ) )
51                tor = tr_torrentFindFromHashString( handle, str );
52            if( tor )
53                torrents[torrentCount++] = tor;
54        }
55    }
56    else /* all of them */
57    {
58        tr_torrent * tor = NULL;
59        const int n = tr_torrentCount( handle );
60        torrents = tr_new0( tr_torrent*, n );
61        while(( tor = tr_torrentNext( handle, tor )))
62            torrents[torrentCount++] = tor;
63    }
64
65    *setmeCount = torrentCount;
66    return torrents;
67}
68
69typedef void( *tor_func )( tr_torrent * tor );
70
71static void callTorrentFunc( tr_handle * h, tr_benc * args_in, tor_func func )
72{
73    int i, torrentCount;
74    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
75    for( i=0; i<torrentCount; ++i )
76        ( *func )( torrents[i] );
77    tr_free( torrents );
78}
79
80static const char*
81torrentStart( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
82{
83    callTorrentFunc( h, args_in, tr_torrentStart );
84    return NULL;
85}
86
87static const char*
88torrentStop( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
89{
90    callTorrentFunc( h, args_in, tr_torrentStop );
91    return NULL;
92}
93
94static const char*
95torrentClose( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
96{
97    callTorrentFunc( h, args_in, tr_torrentClose );
98    return NULL;
99}
100
101static const char*
102torrentVerify( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
103{
104    callTorrentFunc( h, args_in, tr_torrentVerify );
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        const int * f = st->peersFrom;
122        const struct tr_tracker_stat * s = &st->tracker_stat;
123
124        tr_bencDictAddInt( d, "id", tor->uniqueId );
125        tr_bencDictAddInt( d, "status", st->status );
126        tr_bencDictAddInt( d, "error", st->error );
127        tr_bencDictAddStr( d, "errorString", st->errorString );
128        tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
129        tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
130        tr_bencDictAddDouble( d, "percentDone", st->percentDone );
131        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
132        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
133        tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed );
134        tr_bencDictAddDouble( d, "ratio", st->ratio );
135        tr_bencDictAddInt( d, "eta", st->eta );
136        tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
137        tr_bencDictAddInt( d, "peersConnected", st->peersConnected );
138        tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
139        tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
140        tr_bencDictAddInt( d, "seeders", st->seeders );
141        tr_bencDictAddInt( d, "leechers", st->leechers );
142        tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
143        tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
144        tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
145        tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
146        tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
147        tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
148        tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
149        tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
150        tr_bencDictAddInt( d, "haveValid", st->haveValid );
151        tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
152        tr_bencDictAddInt( d, "startDate", st->startDate );
153        tr_bencDictAddInt( d, "activityDate", st->activityDate );
154        t = tr_bencDictAddDict( d, "peersFrom", 4 );
155            tr_bencDictAddInt( t, "cache",    f[TR_PEER_FROM_CACHE] );
156            tr_bencDictAddInt( t, "incoming", f[TR_PEER_FROM_INCOMING] );
157            tr_bencDictAddInt( t, "pex",      f[TR_PEER_FROM_PEX] );
158            tr_bencDictAddInt( t, "tracker",  f[TR_PEER_FROM_TRACKER] );
159        t = tr_bencDictAddDict( d, "tracker_stat", 7 );
160            tr_bencDictAddStr( t, "scrapeResponse", s->scrapeResponse );
161            tr_bencDictAddStr( t, "announceResponse", s->announceResponse );
162            tr_bencDictAddInt( t, "lastScrapeTime", s->lastScrapeTime );
163            tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
164            tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime );
165            tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime );
166            tr_bencDictAddInt( t, "nextManualAnnounceTime", s->nextManualAnnounceTime );
167    }
168
169    /* cleanup */
170    tr_free( torrents );
171    return NULL;
172}
173
174static void
175addFiles( const tr_info * info, tr_benc * files )
176{
177    unsigned int i;
178    for( i=0; i<info->fileCount; ++i )
179    {
180        const tr_file * file = &info->files[i];
181        tr_benc * d = tr_bencListAddDict( files, 4 );
182        tr_bencDictAddInt( d, "length", file->length );
183        tr_bencDictAddStr( d, "name", file->name );
184        tr_bencDictAddInt( d, "priority", file->priority );
185        tr_bencDictAddInt( d, "dnd", file->dnd );
186    }
187}
188
189static void
190addTrackers( const tr_info * info, tr_benc * trackers )
191{
192    int i;
193    for( i=0; i<info->trackerCount; ++i )
194    {
195        const tr_tracker_info * t = &info->trackers[i];
196        tr_benc * d = tr_bencListAddDict( trackers, 3 );
197        tr_bencDictAddInt( d, "tier", t->tier );
198        tr_bencDictAddStr( d, "announce", t->announce );
199        tr_bencDictAddStr( d, "scrape", t->scrape );
200    }
201}
202
203static void
204serializeInfo( const tr_torrent * tor, tr_benc * d )
205{
206    const tr_info * inf = tr_torrentInfo( tor );
207    tr_bencInitDict( d, 14 ); 
208    tr_bencDictAddInt( d, "id", tor->uniqueId );
209    tr_bencDictAddStr( d, "torrent", inf->torrent );
210    tr_bencDictAddStr( d, "hashString", inf->hashString );
211    tr_bencDictAddStr( d, "name", inf->name );
212    tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" );
213    tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
214    tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
215    tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
216    tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
217    tr_bencDictAddInt( d, "pieceSize", inf->pieceSize );
218    tr_bencDictAddInt( d, "pieceCount", inf->pieceCount );
219    tr_bencDictAddInt( d, "totalSize", inf->totalSize );
220    addFiles   ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
221    addTrackers( inf, tr_bencDictAddList( d, "files", inf->trackerCount ) );
222}
223
224static const char*
225torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
226{
227    int i, torrentCount;
228    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
229    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
230
231    for( i=0; i<torrentCount; ++i )
232        serializeInfo( torrents[i], tr_bencListAdd( list ) );
233
234    tr_free( torrents );
235    return NULL;
236}
237
238static const char*
239torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
240{
241    int i, torrentCount;
242    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
243    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
244
245    for( i=0; i<torrentCount; ++i )
246    {
247        tr_torrent * tor = torrents[i];
248        tr_benc * d = tr_bencListAddDict( list, 4 );
249        tr_bencDictAddInt( d, "id", tor->uniqueId );
250        tr_bencDictAddInt( d, "peer-limit",
251                           tr_torrentGetPeerLimit( tor ) );
252        tr_bencDictAddInt( d, "speed-limit-down",
253                           tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
254        tr_bencDictAddInt( d, "speed-limit-up",
255                           tr_torrentGetSpeedLimit( tor, TR_UP ) );
256    }
257
258    tr_free( torrents );
259    return NULL;
260}
261
262static const char*
263torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
264{
265    int i, torrentCount;
266    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
267
268    for( i=0; i<torrentCount; ++i )
269    {
270        int64_t tmp;
271        tr_torrent * tor = torrents[i];
272        if( tr_bencDictFindInt( args_in, "peer-limit", &tmp ) )
273            tr_torrentSetPeerLimit( tor, tmp );
274        if( tr_bencDictFindInt( args_in, "speed-limit-down", &tmp ) )
275            tr_torrentSetSpeedLimit( tor, TR_DOWN, tmp );
276        if( tr_bencDictFindInt( args_in, "speed-limit-up", &tmp ) )
277            tr_torrentSetSpeedLimit( tor, TR_UP, tmp );
278    }
279
280    tr_free( torrents );
281    return NULL;
282}
283
284typedef int( *fileTestFunc )( const tr_torrent * tor, int i );
285
286static int
287testFileHigh( const tr_torrent * tor, int i )
288{
289    return tor->info.files[i].priority == TR_PRI_HIGH;
290}
291static int
292testFileLow( const tr_torrent * tor, int i )
293{
294    return tor->info.files[i].priority == TR_PRI_LOW;
295}
296static int
297testFileNormal( const tr_torrent * tor, int i )
298{
299    return tor->info.files[i].priority == TR_PRI_NORMAL;
300}
301static int
302testFileDND( const tr_torrent * tor, int i )
303{
304    return tor->info.files[i].dnd != 0;
305}
306static int
307testFileDownload( const tr_torrent * tor, int i )
308{
309    return tor->info.files[i].dnd == 0;
310}
311
312static void
313buildFileList( const tr_torrent * tor, tr_benc * dict,
314               const char * key, fileTestFunc func )
315{
316    int i;
317    const int n = tor->info.fileCount;
318    tr_benc * list;
319    int * files = tr_new0( int, n );
320    int fileCount = 0;
321   
322    for( i=0; i<n; ++i )
323        if( func( tor, i ) )
324            files[fileCount++] = i;
325
326    list = tr_bencDictAddList( dict, key, fileCount );
327
328    for( i=0; i<fileCount; ++i )
329        tr_bencListAddInt( list, files[i] );
330
331    tr_free( files );
332}
333
334static const char*
335torrentGetFile( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
336{
337    int i, torrentCount;
338    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
339    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
340
341    for( i=0; i<torrentCount; ++i )
342    {
343        const tr_torrent * tor = torrents[i];
344        tr_benc * d = tr_bencListAddDict( list, 6 );
345        tr_bencDictAddInt( d, "id", tor->uniqueId );
346        buildFileList( tor, d, "priority-high", testFileHigh );
347        buildFileList( tor, d, "priority-low", testFileLow );
348        buildFileList( tor, d, "priority-normal", testFileNormal );
349        buildFileList( tor, d, "download", testFileDownload );
350        buildFileList( tor, d, "no-download", testFileDND );
351    }
352
353    tr_free( torrents );
354    return NULL;
355}
356
357static void
358setFilePriorities( tr_torrent * tor, int priority, tr_benc * list )
359{
360    const int n = tr_bencListSize( list );
361    int i;
362    int64_t tmp;
363    int fileCount = 0;
364    tr_file_index_t * files = tr_new0( tr_file_index_t, n );
365
366    for( i=0; i<n; ++i )
367        if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
368            files[fileCount++] = tmp;
369
370    if( fileCount )
371        tr_torrentSetFilePriorities( tor, files, fileCount, priority );
372
373    tr_free( files );
374}
375
376static void
377setFileDLs( tr_torrent * tor, int do_download, tr_benc * list )
378{
379    const int n = tr_bencListSize( list );
380    int i;
381    int64_t tmp;
382    int fileCount = 0;
383    tr_file_index_t * files = tr_new0( tr_file_index_t, n );
384
385    for( i=0; i<n; ++i )
386        if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
387            files[fileCount++] = tmp;
388
389    if( fileCount )
390        tr_torrentSetFileDLs( tor, files, fileCount, do_download );
391
392    tr_free( files );
393}
394
395static const char*
396torrentSetFile( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
397{
398    int i, torrentCount;
399    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
400
401    for( i=0; i<torrentCount; ++i )
402    {
403        tr_benc * files;
404        tr_torrent * tor = torrents[i];
405
406        if( tr_bencDictFindList( args_in, "priority-high", &files ) )
407            setFilePriorities( tor, TR_PRI_HIGH, files );
408        if( tr_bencDictFindList( args_in, "priority-low", &files ) )
409            setFilePriorities( tor, TR_PRI_LOW, files );
410        if( tr_bencDictFindList( args_in, "priority-normal", &files ) )
411            setFilePriorities( tor, TR_PRI_NORMAL, files );
412        if( tr_bencDictFindList( args_in, "download", &files ) )
413            setFileDLs( tor, TRUE, files );
414        if( tr_bencDictFindList( args_in, "no-download", &files ) )
415            setFileDLs( tor, FALSE, files );
416    }
417
418    tr_free( torrents );
419    return NULL;
420}
421
422/***
423****
424***/
425
426static const char*
427torrentAdd( tr_handle * h, tr_benc * args_in, tr_benc * args_out )
428{
429    const char * filename;
430    if( !tr_bencDictFindStr( args_in, "filename", &filename ) )
431        return "no filename specified";
432    else {
433        int64_t i;
434        int err = 0;
435        const char * str;
436        tr_ctor * ctor;
437        tr_torrent * tor;
438
439        ctor = tr_ctorNew( h );
440        tr_ctorSetMetainfoFromFile( ctor, filename );
441        if( tr_bencDictFindInt( args_in, "autostart", &i ) )
442            tr_ctorSetPaused( ctor, TR_FORCE, !i );
443        if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
444            tr_ctorSetPeerLimit( ctor, TR_FORCE, i );
445        if( tr_bencDictFindStr( args_in, "destination", &str ) )
446            tr_ctorSetDestination( ctor, TR_FORCE, str );
447        tor = tr_torrentNew( h, ctor, &err );
448        tr_ctorFree( ctor );
449
450        if( tor )
451            serializeInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ) );
452        else if( err == TR_EDUPLICATE )
453            return "duplicate torrent";
454        else if( err == TR_EINVALID )
455            return "invalid or corrupt torrent file";
456    }
457
458    return NULL;
459}
460
461/***
462****
463***/
464
465static const char*
466sessionSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
467{
468    int64_t i;
469    const char * str;
470
471    if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
472        tr_sessionSetPeerLimit( h, i );
473    if( tr_bencDictFindInt( args_in, "port", &i ) )
474        tr_sessionSetPublicPort( h, i );
475    if( tr_bencDictFindInt( args_in, "port-forwarding-enabled", &i ) )
476        tr_sessionSetPortForwardingEnabled( h, i );
477    if( tr_bencDictFindInt( args_in, "pex-allowed", &i ) )
478        tr_sessionSetPexEnabled( h, i );
479    if( tr_bencDictFindInt( args_in, "speed-limit-down", &i ) )
480        tr_sessionSetSpeedLimit( h, TR_DOWN, i );
481    if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &i ) )
482        tr_sessionSetSpeedLimitEnabled( h, TR_DOWN, i );
483    if( tr_bencDictFindInt( args_in, "speed-limit-up", &i ) )
484        tr_sessionSetSpeedLimit( h, TR_UP, i );
485    if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &i ) )
486        tr_sessionSetSpeedLimitEnabled( h, TR_UP, i );
487    if( tr_bencDictFindStr( args_in, "encryption", &str ) ) {
488        if( !strcmp( str, "required" ) )
489            tr_sessionSetEncryption( h, TR_ENCRYPTION_REQUIRED );
490        else if( !strcmp( str, "tolerated" ) )
491            tr_sessionSetEncryption( h, TR_PLAINTEXT_PREFERRED );
492        else
493            tr_sessionSetEncryption( h, TR_ENCRYPTION_PREFERRED );
494    }
495
496    return NULL;
497}
498
499static const char*
500sessionGet( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
501{
502    const char * str;
503    tr_benc * d = tr_bencDictAddDict( args_out, "session", 9 );
504
505    tr_bencDictAddInt( d, "peer-limit",
506                          tr_sessionGetPeerLimit( h ) );
507    tr_bencDictAddInt( d, "port",
508                          tr_sessionGetPublicPort( h ) );
509    tr_bencDictAddInt( d, "port-forwarding-enabled",
510                          tr_sessionIsPortForwardingEnabled( h ) );
511    tr_bencDictAddInt( d, "pex-allowed",
512                          tr_sessionIsPexEnabled( h ) );
513    tr_bencDictAddInt( d, "speed-limit-up",
514                          tr_sessionGetSpeedLimit( h, TR_UP ) );
515    tr_bencDictAddInt( d, "speed-limit-up-enabled",
516                          tr_sessionIsSpeedLimitEnabled( h, TR_UP ) );
517    tr_bencDictAddInt( d, "speed-limit-down",
518                          tr_sessionGetSpeedLimit( h, TR_DOWN ) );
519    tr_bencDictAddInt( d, "speed-limit-down-enabled",
520                          tr_sessionIsSpeedLimitEnabled( h, TR_DOWN ) );
521    switch( tr_sessionGetEncryption( h ) ) {
522        case TR_PLAINTEXT_PREFERRED: str = "tolerated"; break;
523        case TR_ENCRYPTION_REQUIRED: str = "required"; break;
524        default: str = "preferred"; break;
525    }
526    tr_bencDictAddStr( d, "encryption", str );
527
528
529   
530    return NULL;
531}
532
533/***
534****
535***/
536
537typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* );
538
539struct request_handler
540{
541    const char * name;
542    handler * func;
543} request_handlers[] = { 
544    { "torrent-start", torrentStart },
545    { "torrent-stop", torrentStop },
546    { "torrent-close", torrentClose },
547    { "torrent-verify", torrentVerify },
548    { "torrent-status", torrentStatus },
549    { "torrent-info", torrentInfo },
550    { "torrent-add", torrentAdd },
551    { "torrent-set", torrentSet },
552    { "torrent-get", torrentGet },
553    { "torrent-set-file", torrentSetFile },
554    { "torrent-get-file", torrentGetFile },
555    { "session-set", sessionSet },
556    { "session-get", sessionGet }
557};
558
559static char*
560request_exec( struct tr_handle * handle,
561              tr_benc          * request,
562              int              * response_len )
563{
564    int64_t i;
565    const char * str;
566    char * out;
567    tr_benc response;
568    tr_benc * headers_in = NULL;
569    tr_benc * body_in = NULL;
570    tr_benc * args_in = NULL;
571    tr_benc * headers_out = NULL;
572    tr_benc * body_out = NULL;
573    tr_benc * args_out = NULL;
574    const char * result = NULL;
575
576    headers_in = tr_bencDictFind( request, "headers" );
577    body_in = tr_bencDictFind( request, "body" );
578    args_in = tr_bencDictFind( body_in, "args" );
579
580    /* build the response skeleton */
581    tr_bencInitDict( &response, 2 );
582    headers_out = tr_bencDictAddDict( &response, "headers", 2 );
583    tr_bencDictAddStr( headers_out, "type", "response" );
584    if( tr_bencDictFindInt( headers_in, "tag", &i ) )
585        tr_bencDictAddInt( headers_out, "tag", i );
586    body_out = tr_bencDictAddDict( &response, "body", 2 );
587    args_out = tr_bencDictAddDict( body_out, "args", 0 );
588
589    /* parse the request */
590    if( !tr_bencDictFindStr( body_in, "name", &str ) )
591        result = "no request name given";
592    else {
593        const int n = TR_N_ELEMENTS( request_handlers );
594        for( i=0; i<n; ++i )
595            if( !strcmp( str, request_handlers[i].name ) )
596                break;
597        result = i==n
598            ? "request name not recognized"
599            : (*request_handlers[i].func)( handle, args_in, args_out );
600    }
601
602    /* serialize & return the response */
603    if( !result )
604        result = "success";
605    tr_bencDictAddStr( body_out, "result", result );
606    out = tr_bencSave( &response, response_len ); /* TODO: json, not benc */
607    tr_bencFree( &response );
608    return out;
609}
610
611char*
612tr_ipc_request_exec( struct tr_handle  * handle,
613                     const void        * request_json,
614                     int                 request_len,
615                     int               * response_len )
616{
617    tr_benc top;
618    int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
619    char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
620    if( have_content )
621        tr_bencFree( &top );
622    return ret;
623}
Note: See TracBrowser for help on using the repository browser.